How to check internet connection with RxJava in Android - android

In my application I want use RxJava and I want check internet connection.
I write below code, but just check first time when application started!
I want check every time and when internet connection lost or available show user!
My class codes :
class InternetConnection {
#Suppress("DEPRECATION")
private fun isConnectedOld(context: Context): Boolean {
val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = connManager.activeNetworkInfo
return networkInfo!!.isConnected
}
#RequiresApi(Build.VERSION_CODES.M)
private fun isConnectedNewApi(context: Context): Boolean {
val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
return capabilities?.hasCapability(NET_CAPABILITY_INTERNET) == true
}
fun isConnected(context: Context): Observable<Boolean> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Observable.just(isConnectedNewApi(context))
} else {
Observable.just(isConnectedOld(context))
}
}
}
Activity codes :
class TestCheckNetworkActivity : AppCompatActivity() {
private lateinit var binding: ActivityTestCheckNetworkBinding
private val internet by lazy { InternetConnection() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTestCheckNetworkBinding.inflate(layoutInflater)
setContentView(binding.root)
internet.isConnected(this)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
binding.checkNetTxt.text = it.toString()
}
}
}
How can I change my codes for check internet for every time, not just when application created ?

Related

Convert Live Data to kotlin flow in jetpack compose

Hey I am new in jetpack compose. I am checking in internet is available or not and consume through live data. Now I started learning jetpack compose so I want to use Flow, So any guys help me to convert this LiveData to flow and use in jetpack compose.
NetworkConnection.kt
import android.app.Application
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkRequest
import androidx.lifecycle.LiveData
class NetworkConnection(private val connectivityManager: ConnectivityManager) : LiveData<Boolean>() {
constructor(application: Application) : this(application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
postValue(true)
}
override fun onLost(network: Network) {
super.onLost(network)
postValue(false)
}
}
override fun onActive() {
super.onActive()
val builder = NetworkRequest.Builder()
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
override fun onInactive() {
super.onInactive()
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
Can someone help me which way of doing recommendations for kotlin flow in jetpack compose.
MainActivity.kt
class MainActivity : ComponentActivity() {
private lateinit var checkNetworkConnection: NetworkConnection
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkNetworkConnection = NetworkConnection(application)
setContent {
SportsResultTheme {
SetupView()
}
}
}
}
I am confused also how can I use flow in my compose in recommendation way. Thanks
NetworkConnection.kt ->
class NetworkConnection(private val connectivityManager: ConnectivityManager) {
init {
registerNetworkCallback()
}
constructor(application: Application) : this(application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)
val stateFlow: StateFlow<State>
get() = _stateFlow
private val _stateFlow: MutableStateFlow<State> = MutableStateFlow(State.Init)
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
_stateFlow.value = State.Available
}
override fun onLost(network: Network) {
super.onLost(network)
_stateFlow.value = State.Gone
}
}
fun registerNetworkCallback(){
val builder = NetworkRequest.Builder()
connectivityManager.registerNetworkCallback(builder.build(), networkCallback)
}
fun unregisterNetworkCallback() {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
sealed interface State {
object Init : State
object Available : State
object Gone : State
}
}
MainActivity.kt
class MainActivity : ComponentActivity() {
private lateinit var checkNetworkConnection: NetworkConnection
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkNetworkConnection = NetworkConnection(application)
setContent {
SportsResultTheme {
checkNetworkConnection.stateFlow.collectAsState()
SetupView()
}
}
}
}
Jetpack compose has function (LiveData.observeAsState()) available to convert LiveData to State that you can use in your Compose UI. You don't have to use Flow if you already have a LiveData in your code base. Pass you live data into the composable and convert it to a state. You can also convert live data to state before you call the SetupView composable and just pass the state itself.
#Composable
fun SetupView(networkConnection : NetworkConnection) {
val isConnected = networkConnection.observeAsState()
if(isConnected) {
// update for connected state
} else {
// handle offline state
}
}

Kotlin check connection in BaseActivity

I have created function to check internet connection in my BaseActivity file but it does not work (redirect user)
Code
Code is commented for better understanding
BaseActivity.kt
open class BaseActivity: AppCompatActivity() {
lateinit var prefManager: PrefManager
override fun attachBaseContext(newBase: Context) {
// my app languages codes...
super.attachBaseContext(localeUpdatedContext)
// check internet connection
// What I'm trying to do here is to redirect user into specific activity when connection is lost (it would be best if we can run it every minute or so.)
if(!isNetworkAvailable()) {
val intent = Intent(newBase, NoInternetActivity::class.java)
startActivity(intent)
finish()
}
}
// internet connection function
fun isNetworkAvailable() : Boolean{
val conManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val internetInfo =conManager.activeNetworkInfo
return internetInfo!=null && internetInfo.isConnected
}
class ContextUtils(base: Context) : ContextWrapper(base) {
companion object {
// my other codes...
}
}
open fun openDialog() {}
}
Any suggestions?
Update
I've made following changes which results in redirecting user to next activity if connection is lost but as it is working with Task Timer it refreshes next activity constantly I need it to redirect only once
open class BaseActivity: AppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
// my app languages codes...
super.attachBaseContext(localeUpdatedContext)
// check connection every 5 seconds
val timer = Timer()
val MILLISECONDS = 5000 //5 seconds
val timerr = timer.schedule(CheckConnection(this), 0, MILLISECONDS.toLong())
Log.d("CheckConnection", timerr.toString())
}
internal class CheckConnection(private val context: Context) : TimerTask() {
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetworkInfo = connectivityManager.activeNetworkInfo
return activeNetworkInfo != null && activeNetworkInfo.isConnected
}
override fun run() {
if (!isNetworkAvailable(context)) {
Log.d("CheckConnection", "DISCONNECTED")
val intent = Intent(context, NoInternetActivity::class.java)
context.startActivity(intent)
} else {
Log.d("CheckConnection", "CONNECTED")
}
}
}
}
PS: I've tried to use finish() after my intent startActivity but I got Unresolved reference: finish

Android Unit testing dataStore

I'm trying to write a test for my view model that gets the data from datastore but I can't figure it out. this is my data store implementation. I save the user data such as email and token when user is sign up or sign in :
class FlowAuthenticationDataStore(context: Context) : AuthenticationDataStore {
private val dataStore = context.createDataStore(name = "user_auth")
private val userEmailKey = preferencesKey<String>(name = "USER_EMAIL")
private val userTokenKey = preferencesKey<String>(name = "USER_TOKEN")
private val userNameKey = preferencesKey<String>(name = "USER_NAME")
private val userIsLoginKey = preferencesKey<Boolean>(name = "USER_IS_LOGIN")
override suspend fun updateUser(userDataStore: UserDataStoreModel) {
dataStore.edit {
it[userEmailKey] = userDataStore.email
it[userTokenKey] = userDataStore.token
it[userNameKey] = userDataStore.name
it[userIsLoginKey] = userDataStore.isLogin
}
}
override fun observeUser(): Flow<UserDataStoreModel> {
return dataStore.data.catch {
if (it is IOException) {
emit(emptyPreferences())
} else {
throw it
}
}.map {
UserDataStoreModel(
it[userIsLoginKey]!!,
it[userNameKey]!!,
it[userEmailKey]!!,
it[userTokenKey]!!
)
}
}
}
and this is my view model. I observe the user data store and if its success and has a data then I update my live data. If there is not data and user is first time to register then my live data is equal to default value from data class :
class SplashScreenViewModel(
private val flowOnBoardingDataStore: FlowAuthenticationDataStore,
private val contextProvider: CoroutineContextProvider,
) :
ViewModel() {
private val _submitState = MutableLiveData<UserDataStoreModel>()
val submitState: LiveData<UserDataStoreModel> = _submitState
fun checkUserLogin() {
viewModelScope.launch {
kotlin.runCatching {
withContext(contextProvider.io) {
flowOnBoardingDataStore.observeUser().collect {
_submitState.value = it
}
}
}.onFailure {
_submitState.value = UserDataStoreModel()
}
}
}
}
and this is my test class:
#ExperimentalCoroutinesApi
class SplashScreenViewModelTest {
private val dispatcher = TestCoroutineDispatcher()
#get:Rule
val rule = InstantTaskExecutorRule()
#get:Rule
val coroutineTestRule = CoroutineTestRule(dispatcher)
#RelaxedMockK
lateinit var flowOnBoardingDataStore: FlowAuthenticationDataStore
private fun createViewModel()=SplashScreenViewModel(flowOnBoardingDataStore,
CoroutineContextProvider(dispatcher,dispatcher)
)
#Before
fun setup() {
MockKAnnotations.init(this)
}
#After
fun tearDown() {
unmockkAll()
}
#Test
fun `when user is already sign in, then state should return model`()=dispatcher.runBlockingTest {
val viewModel=createViewModel()
val userDataStoreModel= UserDataStoreModel(true,"test","test","test")
flowOnBoardingDataStore.updateUser(userDataStoreModel)
viewModel.checkUserLogin()
assertEquals(userDataStoreModel,viewModel.submitState.value)
}
}
This is the result of my test function:
junit.framework.AssertionFailedError:
Expected :UserDataStoreModel(isLogin=true, name=test, email=test, token=test)
Actual :null
I find the solution and I posted here Incase anybody needs it.
The solution is using coEvery to return a fake data with flowOf from the usecase( you don't need to use flowOf , its based on your return data from your use case, in my case it's return a flow):
#Test
fun `when user is already sign in, then state should return user data`()=dispatcher.runBlockingTest {
val userData=UserDataStoreModel(true, Name,
Email,"","")
coEvery { authenticationDataStore.observeUser() }returns flowOf(userData)
val viewModel=createViewModel()
viewModel.checkUserLogin()
assertEquals(userData,viewModel.submitState.value)
}
This is the full test class:
#ExperimentalCoroutinesApi
class SplashScreenViewModelTest {
private val dispatcher = TestCoroutineDispatcher()
#get:Rule
val rule = InstantTaskExecutorRule()
#get:Rule
val coroutineTestRule = CoroutineTestRule(dispatcher)
#RelaxedMockK
lateinit var authenticationDataStore: AuthenticationDataStore
private fun createViewModel()=SplashScreenViewModel(authenticationDataStore,
CoroutineContextProvider(dispatcher,dispatcher)
)
#Before
fun setup() {
MockKAnnotations.init(this)
}
#After
fun tearDown() {
unmockkAll()
}
#Test
fun `when user is already sign in, then state should return user data`()=dispatcher.runBlockingTest {
val userData=UserDataStoreModel(true, Name,
Email,"","")
coEvery { authenticationDataStore.observeUser() }returns flowOf(userData)
val viewModel=createViewModel()
viewModel.checkUserLogin()
assertEquals(userData,viewModel.submitState.value)
}
}

Kotlin MainThread

I'm new in Kotlin.
I have a problem, with "The application may be doing too much work on its main thread".
I have 2 different activity. The principal I use for login, the second for send a get http and receive a json object.
Where is my problem? I wrong to use 2 different activity o the problem is asyncdo? I am in deep sea.
class GitActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.git_activity)
Recycle_view.layoutManager = LinearLayoutManager(this)
Recycle_view.adapter = MainAdapter()
var url = intent.getStringExtra("URL")
doAsync {
fetchJson(url)
uiThread { longToast("Request performed") }
}
}
fun fetchJson(url: String) : List<NameFileList> {
var request = Request.Builder().url(url).build()
val client = OkHttpClient()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
print("sono qui")
print(url)
val body = response?.body()?.string()
print(body)
}
override fun onFailure(call: Call, e: IOException) {
print("Error Failure")
}
})
}
and my Main Class
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
SearchButton.setOnClickListener {
verifyNetwork()
}
}
private fun getUsername(): String {
val username = Username_editText.text.toString()
Log.d("MainActivity", "UserName is + $username")
return username
}
private fun getRepositoryName(): String {
val nameRepository = RepositoryName_editText.text.toString()
Log.d("MainActivity", "UserName is + $nameRepository")
return nameRepository
}
private fun verifyNetwork()
{
if(isConnected(this)){
val url = CreateUrl().createUrl(getUsername(), getRepositoryName())
print(url)
var intent = Intent(this, GitActivity::class.java)
intent.putExtra("URL", url)
startActivity(intent)
}
else {
//POPUP DI ERRORE NETWORK
}
}
private fun isConnected(context: Context): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = cm.activeNetworkInfo
return activeNetwork != null && activeNetwork.isConnectedOrConnecting
}
}
Are your icons / resources appropriately sized for a mobile application? If your assets are too large, inflation could take over the main thread.
You'd better to use Retrofit + Rxjava for handling Network call.
Retrofit :
https://square.github.io/retrofit/
RxJava :
https://github.com/ReactiveX/RxJava
You can also refer this link for check example: How to get the response URL from Retrofit?

Socket connection in background

I need to make an application where, while the user is authorized, it keeps the socket connection until it is logged out. For this purpose, a foreground service is created, which starts after the authorization of the user, and stops when it is logged out. It implements connection and reconnection on the socket.
All works well until you press the power button and turn off the charging. After this, the user stops receiving pongs from the server and the SocketTimeoutException is received on the OkHttp, and also stops receiving messages on the socket. On JavaWebsocket, The connection was closed because the other endpoint did not respond with a pong in time is received, after which you can successfully create a new socket connection, but it will repeat the same problem in the loop.
In the settings, the optimization of the battery for this application was disabled. What can I do to make a stable connection socket work in the background?
Implementation of activity:
class MainActivity : BaseFragmentPermissionActivity(), MainMvpView {
private var mIsSocketBound = false
private var mSocketBroadcastReceiver = SocketBroadcastReceiver(this)
private var mSocketConnection = SocketConnection(this)
private var mSocketService: SocketService? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
doBindService()
}
private fun doBindService() {
bindService(Intent(this, SocketService::class.java), mSocketConnection, Context.BIND_AUTO_CREATE)
mIsSocketBound = true
}
override fun onStart() {
super.onStart()
...
mSocketService?.doStopForeground()
}
override fun onStop() {
mSocketService?.doStartForeground()
...
super.onStop()
}
override fun onDestroy() {
doUnbindService()
...
super.onDestroy()
}
private fun doUnbindService() {
if (mIsSocketBound) {
unbindService(mSocketConnection)
mIsSocketBound = false
mSocketService = null
}
}
class SocketConnection(mainActivity: MainActivity) : ServiceConnection {
private val mMainActivity: WeakReference<MainActivity> = WeakReference(mainActivity)
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val socketService = (service as SocketService.LocalBinder).getService()
mMainActivity.get()?.mSocketService = socketService
if (socketService.isForeground()) {
socketService.doStopForeground()
}
}
override fun onServiceDisconnected(name: ComponentName?) {
mMainActivity.get()?.mSocketService = null
}
}
}
Implementation of service:
class SocketService : Service(), MvpErrorHandler {
private val mConnectingHandler = Handler()
private val mConnectingTask = ConnectingTask(this)
private var mIsRunningForeground = false
override fun onBind(intent: Intent?): IBinder {
startService(Intent(this, SocketService::class.java))
return mBinder
}
override fun onCreate() {
super.onCreate()
DaggerServiceComponent.builder()
.serviceModule(ServiceModule(this))
.applicationComponent(PatrolApplication.applicationComponent)
.build()
.inject(this)
startConnecting()
...
}
override fun onDestroy() {
...
stopConnecting()
super.onDestroy()
}
private fun startConnecting() {
if (!mIsConnecting) {
mIsConnecting = true
mConnectingHandler.post(mConnectingTask)
}
}
private fun stopConnecting() {
mConnectingHandler.removeCallbacks(mConnectingTask)
mIsConnecting = false
}
private fun openConnection() {
mCompositeDisposable.add(mDataManager.getSocketToken()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(false, this, {
stopConnecting()
mDataManager.openSocketConnection(it.token)
}, {
mConnectingHandler.postDelayed(mConnectingTask, RECONNECT_TIME.toLong())
return#subscribe ErrorHandlerUtil.handleGetSocketError(it, this)
}))
}
class ConnectingTask(socketService: SocketService) : Runnable {
private val mSocketService: WeakReference<SocketService> = WeakReference(socketService)
override fun run() {
mSocketService.get()?.openConnection()
}
}
}
Implementation of SocketHelper using JavaWebsocket:
class CustomApiSocketHelper #Inject constructor() : ApiSocketHelper {
private var mCustomSocketClient: WebSocketClient? = null
override fun openSocketConnection(token: String) {
mCustomSocketClient = CustomSocketClient(URI(CONNECTION_URL + token))
mCustomSocketClient?.connect()
}
override fun sendMessage(text: String) {
if (mCustomSocketClient?.isOpen == true) {
try {
mCustomSocketClient?.send(text)
} catch (t: Throwable) {
Log.e(TAG, Log.getStackTraceString(t))
Crashlytics.logException(t)
}
}
}
override fun closeSocketConnection() {
mCustomSocketClient?.close(CLOSE_REASON_OK)
}
class CustomSocketClient(uri: URI) : WebSocketClient(uri) {
init {
connectionLostTimeout = PING_TIMEOUT
}
override fun onOpen(handshakedata: ServerHandshake?) {
sendBroadcast(SocketActionType.OPEN.action)
}
override fun onMessage(message: String?) {
sendBroadcast(SocketActionType.MESSAGE.action, message)
}
override fun onClose(code: Int, reason: String?, remote: Boolean) {
if (code != CLOSE_REASON_OK) {
//call startConnecting() in service
sendBroadcast(SocketActionType.CLOSE.action)
}
}
override fun onError(ex: Exception?) {
sendBroadcast(SocketActionType.FAILURE.action)
}
private fun sendBroadcast(type: Int) {
val intent = Intent().apply { action = SOCKET_BROADCAST_ACTION }
intent.putExtra(SOCKET_MESSAGE_TYPE, type)
LocalBroadcastManager.getInstance(CustomApplication.application).sendBroadcast(intent)
}
private fun sendBroadcast(type: Int, text: String?) {
val intent = Intent().apply { action = SOCKET_BROADCAST_ACTION }
intent.putExtra(SOCKET_MESSAGE_TYPE, type)
intent.putExtra(SOCKET_MESSAGE, text)
LocalBroadcastManager.getInstance(CustomApplication.application).sendBroadcast(intent)
}
}
}
Implementation of SocketHelper using OkHttp:
class CustomApiSocketHelper #Inject constructor() : ApiSocketHelper {
private var mCustomSocketClient: WebSocket? = null
override fun openSocketConnection(token: String) {
val request = Request.Builder()
.url(CONNECTION_URL + token)
.build()
mCustomSocketClient = CustomApplication.applicationComponent.authorizedClient().newWebSocket(request, CustomSocketClient())
}
override fun sendMessage(text: String) {
mPatrolSocketClient?.send(text)
}
override fun closeSocketConnection() {
mCustomSocketClient?.close(CLOSE_REASON_OK, null)
}
class CustomSocketClient : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
super.onOpen(webSocket, response)
sendBroadcast(SocketActionType.OPEN.action)
}
override fun onMessage(webSocket: WebSocket, text: String) {
super.onMessage(webSocket, text)
sendBroadcast(SocketActionType.MESSAGE.action, text)
}
override fun onClosed(webSocket: WebSocket?, code: Int, reason: String?) {
super.onClosed(webSocket, code, reason)
if (code != CLOSE_REASON_OK) {
sendBroadcast(SocketActionType.CLOSE.action)
}
}
override fun onFailure(webSocket: WebSocket?, t: Throwable?, response: Response?) {
super.onFailure(webSocket, t, response)
sendBroadcast(SocketActionType.FAILURE.action)
}
private fun sendBroadcast(type: Int) {
val intent = Intent().apply { action = SOCKET_BROADCAST_ACTION }
intent.putExtra(SOCKET_MESSAGE_TYPE, type)
LocalBroadcastManager.getInstance(CustomApplication.application).sendBroadcast(intent)
}
private fun sendBroadcast(type: Int, text: String?) {
val intent = Intent().apply { action = SOCKET_BROADCAST_ACTION }
intent.putExtra(SOCKET_MESSAGE_TYPE, type)
intent.putExtra(SOCKET_MESSAGE, text)
LocalBroadcastManager.getInstance(CustomApplication.application).sendBroadcast(intent)
}
}
}
...
#Provides
#Singleton
#Named(AUTHORIZED_CLIENT)
fun provideAuthorizedClient(builder: OkHttpClient.Builder, interceptor: Interceptor, authenticator: Authenticator): OkHttpClient = builder
.addInterceptor(interceptor)
.authenticator(authenticator)
.pingInterval(PING_TIMEOUT.toLong(), TimeUnit.SECONDS)
.build()
#Provides
#Singleton
fun provideOkHttpBuilder() = CustomApiHelper.getOkHttpBuilder()
fun getOkHttpBuilder(): OkHttpClient.Builder {
val builder = OkHttpClient.Builder()
builder.readTimeout(NETWORK_CALL_TIMEOUT, TimeUnit.SECONDS)
builder.writeTimeout(NETWORK_CALL_TIMEOUT, TimeUnit.SECONDS)
if (BuildConfig.DEBUG) {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
builder.addInterceptor(logger)
}
return builder
}
After some research and testing on different devices, it was found that for stable operation on the network, it is necessary that the device is charging or has a screen enabled. In the other case, neither PARTIAL_WAKE_LOCK nor the disabling of battery optimization in the settings itself can solve the problem.
The recommended way to solve this problem is to add this code to your activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
This prevents the screen from turning off and provides a stable socket connection. But we still have the situation that the user can press the power button. And, if at this moment the device is charging, everything will work as before, but otherwise, we will get the socket disconnect. To solve this problem, you need to periodically wake the device, in order to support the ping-pong process. This is not a recommended solution because it will lead to battery draining, and can not guarantee 100% performance, but if this moment is critical for you, then you can use this solution. You need to add this code, in a suitable place for you, in this example is used at the time of ping.
#Suppress("DEPRECATION")
override fun onWebsocketPing(conn: WebSocket?, f: Framedata?) {
if (mSocketWakeLock == null) {
mSocketWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK or PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG)
}
mSocketWakeLock?.takeIf { !it.isHeld }?.run { acquire(WAKE_TIMEOUT) }
super.onWebsocketPing(conn, f)
mSocketWakeLock?.takeIf { it.isHeld }?.run { release() }
}
Using this solution, on the test devices socket connection, with good Internet, stays stable for 2 hours or more. Without it, it is constantly disconnect.

Categories

Resources