From ee8ae23d5fb49ba2f479befce03df509f93ba2cb Mon Sep 17 00:00:00 2001 From: Gaurav Ujjwal Date: Sun, 31 Jul 2022 22:33:29 +0530 Subject: [PATCH] Refactor connection initialization Until now, connection was started at the very end of onCreate(). As a result components like Dispatcher could not rely on VncViewModel's profile during their initialization. Now initialization happen at the beginning. It also comes with a tiny bit of performance improvement. Receiver thread can now start the connection early, while main thread is still creating the UI. --- .../com/gaurav/avnc/ui/vnc/VncActivityTest.kt | 4 +- .../com/gaurav/avnc/ui/vnc/VncActivity.kt | 41 ++++++++++--------- .../com/gaurav/avnc/viewmodel/VncViewModel.kt | 16 ++++---- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/app/src/androidTest/java/com/gaurav/avnc/ui/vnc/VncActivityTest.kt b/app/src/androidTest/java/com/gaurav/avnc/ui/vnc/VncActivityTest.kt index 9ff2c76..c229457 100644 --- a/app/src/androidTest/java/com/gaurav/avnc/ui/vnc/VncActivityTest.kt +++ b/app/src/androidTest/java/com/gaurav/avnc/ui/vnc/VncActivityTest.kt @@ -9,7 +9,6 @@ package com.gaurav.avnc.ui.vnc import android.content.Context -import android.content.Intent import android.view.inputmethod.InputMethodManager import androidx.test.core.app.ActivityScenario import androidx.test.espresso.Espresso.onIdle @@ -36,8 +35,7 @@ class VncActivityTest { testServer.start() val profile = ServerProfile(host = testServer.host, port = testServer.port) - val intent = Intent(targetContext, VncActivity::class.java) - .putExtra("com.gaurav.avnc.server_profile", profile) + val intent = createVncIntent(targetContext, profile) ActivityScenario.launch(intent).use { onView(withId(R.id.frame_view)).checkWillBeDisplayed() // Wait for connection diff --git a/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt index 3e912e0..12241ed 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/vnc/VncActivity.kt @@ -41,10 +41,14 @@ import java.lang.ref.WeakReference private const val PROFILE_KEY = "com.gaurav.avnc.server_profile" +fun createVncIntent(context: Context, profile: ServerProfile): Intent { + return Intent(context, VncActivity::class.java).apply { + putExtra(PROFILE_KEY, profile) + } +} + fun startVncActivity(source: Activity, profile: ServerProfile) { - val intent = Intent(source, VncActivity::class.java) - intent.putExtra(PROFILE_KEY, profile) - source.startActivity(intent) + source.startActivity(createVncIntent(source, profile)) } fun startVncActivity(source: Activity, uri: VncUri) { @@ -59,7 +63,7 @@ fun startVncActivity(source: Activity, uri: VncUri) { */ class VncActivity : AppCompatActivity() { - private val profile by lazy { loadProfile() } + private lateinit var profile: ServerProfile val viewModel by viewModels() lateinit var binding: ActivityVncBinding private val dispatcher by lazy { Dispatcher(this) } @@ -69,27 +73,29 @@ class VncActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + profile = loadProfile() + viewModel.initConnection(profile) + + //Main UI binding = DataBindingUtil.setContentView(this, R.layout.activity_vnc) binding.viewModel = viewModel binding.lifecycleOwner = this + binding.frameView.initialize(this) + viewModel.frameViewRef = WeakReference(binding.frameView) setupLayout() - - binding.frameView.initialize(this) - binding.retryConnectionBtn.setOnClickListener { retryConnection() } - - //Drawers setupDrawerLayout() + + //Buttons binding.keyboardBtn.setOnClickListener { showKeyboard(); closeDrawers() } binding.zoomResetBtn.setOnClickListener { viewModel.resetZoom(); closeDrawers() } binding.virtualKeysBtn.setOnClickListener { virtualKeys.show(); closeDrawers() } + binding.retryConnectionBtn.setOnClickListener { retryConnection() } - //ViewModel setup - viewModel.frameViewRef = WeakReference(binding.frameView) + //Observers viewModel.credentialRequest.observe(this) { showCredentialDialog() } viewModel.sshHostKeyVerifyRequest.observe(this) { showHostKeyDialog() } viewModel.state.observe(this) { onClientStateChanged(it) } - viewModel.initConnection(profile) //Should be called after observers has been setup } override fun onResume() { @@ -116,14 +122,11 @@ class VncActivity : AppCompatActivity() { private fun loadProfile(): ServerProfile { val profile = intent.getParcelableExtra(PROFILE_KEY) - if (profile != null) { - // Make a copy to avoid modifying intent's instance, - // because we may need the original if we have to retry connection. - return profile.copy() - } + check(profile != null) { "ServerProfile is missing from VncActivity Intent" } - Log.e(javaClass.simpleName, "No connection information was passed through Intent.") - return ServerProfile() + // Make a copy to avoid modifying intent's instance, + // because we may need the original if we have to retry connection. + return profile.copy() } private fun retryConnection() { diff --git a/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt b/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt index 89f5262..8491fbb 100644 --- a/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt +++ b/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt @@ -92,7 +92,7 @@ class VncViewModel(app: Application) : BaseViewModel(app), VncClient.Observer { /** * [ServerProfile] used for current connection. */ - var profile = ServerProfile() + var profile = ServerProfile(); private set /** * We have two places for connection state (both are synced): @@ -167,16 +167,14 @@ class VncViewModel(app: Application) : BaseViewModel(app), VncClient.Observer { /** * Initialize VNC connection using given profile. - * [initConnection] can be called multiple times due to activity restarts. + * It may be called multiple times due to activity restarts. */ fun initConnection(profile: ServerProfile) { - if (state.value != State.Created) - return - - this.profile = profile - state.value = State.Connecting - - launchConnection() + if (state.value == State.Created) { + state.value = State.Connecting + this.profile = profile + launchConnection() + } } private fun launchConnection() {