From f1db0f2c8f6f7780f4e4029feea0a6d6d231560f Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 21 Dec 2018 14:53:12 +0800 Subject: [PATCH] Refactor using ViewModel --- build.gradle | 1 + mobile/build.gradle | 4 ++ mobile/src/main/AndroidManifest.xml | 1 - .../java/be/mygod/vpnhotspot/MainActivity.kt | 27 ++++-------- ...ntMonitorService.kt => ClientViewModel.kt} | 42 +++++++------------ .../vpnhotspot/client/ClientsFragment.kt | 24 +++-------- 6 files changed, 34 insertions(+), 65 deletions(-) rename mobile/src/main/java/be/mygod/vpnhotspot/client/{ClientMonitorService.kt => ClientViewModel.kt} (69%) diff --git a/build.gradle b/build.gradle index 527e29ff..0f13fc70 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ apply plugin: 'com.github.ben-manes.versions' buildscript { ext { kotlinVersion = '1.3.11' + lifecycleVersion = '2.0.0' roomVersion = '2.0.0' } repositories { diff --git a/mobile/build.gradle b/mobile/build.gradle index c5e8081d..a55981aa 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -58,11 +58,14 @@ android { } dependencies { + kapt "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion" kapt "androidx.room:room-compiler:$roomVersion" implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "androidx.browser:browser:1.0.0" implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' implementation "androidx.core:core-ktx:1.0.1" + implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" implementation "androidx.preference:preference:1.0.0" implementation "androidx.room:room-runtime:$roomVersion" implementation 'com.github.luongvo:BadgeView:1.1.5' @@ -74,6 +77,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" baseImplementation 'com.android.billingclient:billing:1.2' baseImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.7' + testImplementation "androidx.arch.core:core-testing:$lifecycleVersion" testImplementation "androidx.room:room-testing:$roomVersion" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index d708600d..29528d78 100644 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -82,7 +82,6 @@ - () + if (RepeaterService.supported) ServiceForegroundConnector(this, model, RepeaterService::class) + model.clients.observe(this, Observer> { badge.badgeNumber = it.size }) SmartSnackbar.Register(lifecycle, binding.fragmentHolder) } @@ -85,17 +87,6 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS else -> false } - override fun onServiceConnected(name: ComponentName?, service: IBinder?) { - clients = service as ClientMonitorService.Binder - service.clientsChanged[this] = { badge.badgeNumber = it.size } - } - - override fun onServiceDisconnected(name: ComponentName?) { - val clients = clients ?: return - this.clients = null - clients.clientsChanged -= this - } - private fun displayFragment(fragment: Fragment) = supportFragmentManager.beginTransaction().replace(R.id.fragmentHolder, fragment).commitAllowingStateLoss() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientMonitorService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientViewModel.kt similarity index 69% rename from mobile/src/main/java/be/mygod/vpnhotspot/client/ClientMonitorService.kt rename to mobile/src/main/java/be/mygod/vpnhotspot/client/ClientViewModel.kt index 19b7acfa..44d155b4 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientMonitorService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientViewModel.kt @@ -1,24 +1,20 @@ package be.mygod.vpnhotspot.client -import android.app.Service -import android.content.* +import android.content.ComponentName +import android.content.IntentFilter +import android.content.ServiceConnection import android.net.wifi.p2p.WifiP2pDevice import android.os.IBinder +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.RepeaterService import be.mygod.vpnhotspot.net.IpNeighbour -import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor import be.mygod.vpnhotspot.net.TetheringManager -import be.mygod.vpnhotspot.util.StickyEvent1 +import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor import be.mygod.vpnhotspot.util.broadcastReceiver -import be.mygod.vpnhotspot.util.stopAndUnbind - -class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Callback { - inner class Binder : android.os.Binder() { - val clientsChanged = StickyEvent1 { clients } - } - private val binder = Binder() - override fun onBind(intent: Intent?) = binder +class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callback { private var tetheredInterfaces = emptySet() private val receiver = broadcastReceiver { _, intent -> val extras = intent.extras ?: return@broadcastReceiver @@ -30,11 +26,7 @@ class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Ca private var repeater: RepeaterService.Binder? = null private var p2p: Collection = emptyList() private var neighbours = emptyList() - private var clients = emptyList() - private set(value) { - field = value - binder.clientsChanged(value) - } + val clients = MutableLiveData>() private fun populateClients() { val clients = HashMap, Client>() @@ -53,7 +45,7 @@ class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Ca } client.ip += Pair(neighbour.ip, neighbour.state) } - this.clients = clients.values.sortedWith(compareBy { it.iface }.thenBy { it.mac }) + this.clients.postValue(clients.values.sortedWith(compareBy { it.iface }.thenBy { it.mac })) } private fun refreshP2p() { @@ -62,20 +54,14 @@ class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Ca populateClients() } - override fun onCreate() { - super.onCreate() - if (RepeaterService.supported) { - bindService(Intent(this, RepeaterService::class.java), this, Context.BIND_AUTO_CREATE) - } + init { + app.registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED)) IpNeighbourMonitor.registerCallback(this) - registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED)) } - override fun onDestroy() { - unregisterReceiver(receiver) + override fun onCleared() { IpNeighbourMonitor.unregisterCallback(this) - if (RepeaterService.supported) stopAndUnbind(this) - super.onDestroy() + app.unregisterReceiver(receiver) } override fun onServiceConnected(name: ComponentName?, service: IBinder?) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt index d8632025..0ff5b681 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt @@ -1,10 +1,7 @@ package be.mygod.vpnhotspot.client -import android.content.ComponentName import android.content.DialogInterface -import android.content.ServiceConnection import android.os.Bundle -import android.os.IBinder import android.text.format.DateUtils import android.text.format.Formatter import android.util.LongSparseArray @@ -19,6 +16,9 @@ import androidx.core.os.bundleOf import androidx.databinding.BaseObservable import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.lifecycle.get import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.ListAdapter @@ -31,13 +31,12 @@ import be.mygod.vpnhotspot.databinding.ListitemClientBinding import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor import be.mygod.vpnhotspot.net.monitor.TrafficRecorder import be.mygod.vpnhotspot.room.* -import be.mygod.vpnhotspot.util.ServiceForegroundConnector import be.mygod.vpnhotspot.util.computeIfAbsentCompat import be.mygod.vpnhotspot.util.toPluralInt import be.mygod.vpnhotspot.widget.SmartSnackbar import java.text.NumberFormat -class ClientsFragment : Fragment(), ServiceConnection { +class ClientsFragment : Fragment() { class NicknameDialogFragment : AlertDialogFragment() { companion object { const val KEY_MAC = "mac" @@ -198,7 +197,6 @@ class ClientsFragment : Fragment(), ServiceConnection { private lateinit var binding: FragmentClientsBinding private val adapter = ClientAdapter() - private var clients: ClientMonitorService.Binder? = null private var rates = HashMap, TrafficRate>() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -210,21 +208,11 @@ class ClientsFragment : Fragment(), ServiceConnection { binding.swipeRefresher.setOnRefreshListener { IpNeighbourMonitor.instance?.flush() } - ServiceForegroundConnector(this, this, ClientMonitorService::class) + ViewModelProviders.of(requireActivity()).get().clients.observe(this, + Observer> { adapter.submitList(it.toMutableList()) }) return binding.root } - override fun onServiceConnected(name: ComponentName?, service: IBinder?) { - clients = service as ClientMonitorService.Binder - service.clientsChanged[this] = { adapter.submitList(it.toMutableList()) } - } - - override fun onServiceDisconnected(name: ComponentName?) { - val clients = clients ?: return - clients.clientsChanged -= this - this.clients = null - } - override fun onStart() { super.onStart() // we just put these two thing together as this is the only place we need to use this event for now