san
02/18/2021, 7:01 AMKy
02/19/2021, 3:36 AMDependencies.kt
file in buildSrc
.
In this file i’ve declared my androidGradlePlugin dependency
const val androidGradlePlugin = "com.android.tools.build:gradle:7.0.0-alpha06"
These values are recognized in my module level build.gradle files but trying to add it to my project level build.gradle.kts file, the import is unresolved. Is it not possible for the project-level gradle file to pull these dependency strings from buildSrc?
project level build.gradle.kts
dependencies {
classpath(Libs.androidGradlePlugin)
}
luke_c
02/19/2021, 11:39 AMHttpLoggingInterceptor
on a signed release build? I’ve set debuggable to true, and tried on the emulator and 2 physical devices (OnePlus and Samsung) but no matter what I do I can’t see logs from it, I can see them fine on a debug build
Here’s how the logger is being added:
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(headerInterceptor)
.build()
Slackbot
02/19/2021, 8:51 PMpascalchidi
02/20/2021, 1:47 PMspierce7
02/21/2021, 3:07 AMJason Inbody
02/22/2021, 1:14 AM.
├── build
│ ├── libs
│ │ └── buildSrc.jar
│ ├── source-roots
│ │ └── buildSrc
│ │ └── source-roots.txt
│ └── tmp
│ └── jar
│ └── MANIFEST.MF
├── build.gradel.kts
└── src
└── main
└── java
└── Dependencies.kt
In Dependencies.kt
object Versions {
val kotlin = "1.2.21"
const val ktLint = "0.40.0"
}
object Deps {
const val androidGradlePlugin = "com.android.tools.build:gradle:7.0.0-alpha05"
const val ktLint = "com.pinterest:ktlint:${Versions.ktLint}"
object GoogleMaps {
const val maps = "com.google.android.libraries.maps:maps:3.1.0-beta"
const val mapsKtx = "com.google.maps.android:maps-v3-ktx:2.2.0"
}
}
and in my app build.gradle
dependencies {
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0'
implementation Deps.GoogleMaps.maps
implementation Deps.GoogleMaps.mapsKtx
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
Android studio auto detects my Google maps objects but I get Build file
'/Users/jasoninbody/AndroidStudioProjects/FinAquaticRentals/app/build.gradle' line: 52A problem occurred evaluating project ':app'.
> Could not get unknown property 'Deps' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
Jason Inbody
02/22/2021, 1:16 AMDeepak Gahlot
02/22/2021, 10:00 AMMjahangiry75
02/22/2021, 12:08 PMbinding = null
binding.recyclerview.adapter = null
adapter = null
but the leak doesn't fixjefbit
02/22/2021, 5:08 PMjust6chill yt
02/22/2021, 6:43 PMheisenberg
02/23/2021, 2:48 AMTarun Chawla
02/23/2021, 9:32 AMSamir Basnet
02/23/2021, 9:56 AMpackage com.view9.legalremit.ui.login
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
import com.view9.legalremit.R
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class LoginActivityUiTest{
@Test
fun is_ActivityInView() {
val activityScenario = ActivityScenario.launch(LoginActivity::class.java)
onView(withId(R.id.container)).check(matches(isDisplayed()))
}
}
Above is my first Expresso test to check if an activity is in View. R.id.container here container is the id of the root layout of the Login Xml . But when i test it on my real Android device it fails with error: androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with id is <com.view9.legalremit:id/container> . What am i doing wrong ?ConorG
02/23/2021, 10:39 AMDefaultLifecycleObserver
that can observe the entire Fragment lifecycle and not just the Fragment View Lifecycle?
I ask because I want to get my team on-board with using FragmentFactory. Some have pushed back citing that it’s awkward having to remember to set it before calling onCreate
and unset it in onDestroy
. I was able to somewhat alleviate the issue by creating a DefaultLifecycleObserver
that can unset it, and also register a FragmentLifecycleCallbacks
so in onFragmentCreated
I can check savedInstanceState
to determine if recovering from process death where I can set the required Factory again.
If I could hook into the Fragment’s onCreate
from the get-go I think it would be possible to just set the Factory once, like in an init
block, then the developer doesn’t have to remember to do any more maintenance on it.
@Ian Lake?George Theocharis
02/23/2021, 10:54 AM1.3.0
?luke_c
02/23/2021, 3:20 PMobject ExampleObjectHolder {
lateinit var repository: Repository
fun initialize(client: Client) {
this.repository = Repository(bffClient)
this.analytics = analyticsClient
}
}
We have a top-level function that calls it, and then starts an Activity
fun startFlow(host: Activity) {
ExampleObjectHolder.initialize(ServiceLocator.instance().client)
host.startActivityForResult(Flow.packIntent(host), REQUEST_CODE)
}
Then inside our Activity we have a ViewModel which gets the dependency from that object
private val viewModel by viewModels<FlowViewModel> {
FlowViewModelFactory(repository = ExampleObjectHolder.repository)
}
This is the point where it’s crashing, but I can’t figure out why because it’s initialized immediately before starting the Activity and the ViewModel accessing it. It’s also only crashing for a very small amount of users.Orfeo Ciano
02/23/2021, 3:40 PMViewModel
for UI Events (i.e. show a snackbar or navigate to another screen)
class MyViewModel(
private val shouldGoToX: ShouldGoToXUseCase
) : ViewModel() {
private val eventChannel = BroadcastChannel<MyEvent>(Channel.BUFFERED)
val events = eventChannel.asFlow()
fun onCreate() = viewModelScope.launch {
delay(3_000L)
val navigationEvent = if (shouldGoToX()) {
MyEvent.NavigateToX
} else {
MyEvent.NavigateToY
}
eventChannel.offer(navigationEvent)
}
}
internal sealed class MyEvent {
object NavigateToX : MyEvent()
object NavigateToY : MyEvent()
}
And here is my test class
internal class MyViewModelTest {
@get:Rule
val testInstantTaskExecutorRule = InstantTaskExecutorRule()
@get:Rule
val testCoroutineRule = TestCoroutineRule()
private val shouldGoToX = mockk<ShouldGoToXUseCase>()
private val viewModel = MyViewModel(shouldGoToX)
@Test
fun `GIVEN the user should go to X WHEN starting the screen THEN the user should see the X Screen`() =
testCoroutineRule.runBlockingTest {
//GIVEN
coEvery { shouldGoToX() } returns false
//WHEN
viewModel.onCreate()
val events = viewModel.events.toList()
//THEN
assertEquals(MyEvent.NavigateToX, events.first())
}
}
Few questions:
1. Any observations about the approach (events sent through a BroadcastChannel
?
2. I'm currently getting this error in the tests, but I've correctly set the test coroutines stuff java.lang.IllegalStateException: This job has not completed yet
. Am I doing something wrong there?Ellen Spertus
02/23/2021, 8:01 PMvar args = GameWonFragmentArgs.fromBundle(requireArguments())
instead of:
var args = GameWonFragmentArgs.fromBundle(arguments!!)
I understand it eliminates the ugly !!
, but it still will likely lead to an error (IllegalStateException
rather than NullPointerException
). This was asked on Stack Overflow but not really answered. ScoreFragmentArgs.fromBundle(requireArguments())Alfred Caguioa
02/24/2021, 12:44 AMTiago Nunes
02/24/2021, 6:08 PM@HiltViewModel
class SomeViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
): ViewModel() {
val argument: Argument =
savedStateHandle[ParentFragmentArgs::argument.name]!!
}
However, this does not work with SharedViewModel (
private val viewModel: SomeSharedViewModel by activityViewModels()
)
I think I understand why. This ViewModel isn't scoped to the Fragment, but to the Activity, so it probably gets the savedState of the Activity instead of the Fragment's (right?)Aditya Patnaik
02/24/2021, 7:13 PMheisenberg
02/25/2021, 3:36 AMUmar Ata
02/25/2021, 9:31 AMRajat
02/25/2021, 3:19 PMluke_c
02/25/2021, 3:53 PMwhenStarted
?
viewLifecycleOwner.lifecycleScope.launch {
val response = fetchConfig()
when (response) {
is ConfigResponse -> {
whenStarted {
goToNextScreen()
}
}
Error -> showError()
}
}
Chetan Tuteja
02/25/2021, 5:12 PMShivam Sethi
02/25/2021, 6:44 PMShivam Sethi
02/25/2021, 6:47 PMShivam Sethi
02/25/2021, 6:47 PMIan Lake
02/25/2021, 6:54 PMShivam Sethi
02/25/2021, 7:01 PM