architecture-samples | A collection of samples to discuss and showcase different architectural tools and patterns for Andro | Architecture library

 by   android Kotlin Version: Current License: Apache-2.0

kandi X-RAY | architecture-samples Summary

architecture-samples is a Kotlin library typically used in Architecture applications. architecture-samples has no bugs, it has no vulnerabilities, it has a Permissive License and it has medium support. You can download it from GitHub.
A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.
    Support
      Quality
        Security
          License
            Reuse
            Support
              Quality
                Security
                  License
                    Reuse

                      kandi-support Support

                        summary
                        architecture-samples has a medium active ecosystem.
                        summary
                        It has 42429 star(s) with 11459 fork(s). There are 2429 watchers for this library.
                        summary
                        It had no major release in the last 6 months.
                        summary
                        There are 117 open issues and 331 have been closed. On average issues are closed in 2273 days. There are 63 open pull requests and 0 closed requests.
                        summary
                        It has a neutral sentiment in the developer community.
                        summary
                        The latest version of architecture-samples is current.
                        architecture-samples Support
                          Best in #Architecture
                            Average in #Architecture
                            architecture-samples Support
                              Best in #Architecture
                                Average in #Architecture

                                  kandi-Quality Quality

                                    summary
                                    architecture-samples has 0 bugs and 0 code smells.
                                    architecture-samples Quality
                                      Best in #Architecture
                                        Average in #Architecture
                                        architecture-samples Quality
                                          Best in #Architecture
                                            Average in #Architecture

                                              kandi-Security Security

                                                summary
                                                architecture-samples has no vulnerabilities reported, and its dependent libraries have no vulnerabilities reported.
                                                summary
                                                architecture-samples code analysis shows 0 unresolved vulnerabilities.
                                                summary
                                                There are 0 security hotspots that need review.
                                                architecture-samples Security
                                                  Best in #Architecture
                                                    Average in #Architecture
                                                    architecture-samples Security
                                                      Best in #Architecture
                                                        Average in #Architecture

                                                          kandi-License License

                                                            summary
                                                            architecture-samples is licensed under the Apache-2.0 License. This license is Permissive.
                                                            summary
                                                            Permissive licenses have the least restrictions, and you can use them in most projects.
                                                            architecture-samples License
                                                              Best in #Architecture
                                                                Average in #Architecture
                                                                architecture-samples License
                                                                  Best in #Architecture
                                                                    Average in #Architecture

                                                                      kandi-Reuse Reuse

                                                                        summary
                                                                        architecture-samples releases are not available. You will need to build from source code and install.
                                                                        summary
                                                                        Installation instructions are not available. Examples and code snippets are available.
                                                                        summary
                                                                        It has 4754 lines of code, 349 functions and 92 files.
                                                                        summary
                                                                        It has medium code complexity. Code complexity directly impacts maintainability of the code.
                                                                        architecture-samples Reuse
                                                                          Best in #Architecture
                                                                            Average in #Architecture
                                                                            architecture-samples Reuse
                                                                              Best in #Architecture
                                                                                Average in #Architecture
                                                                                  Top functions reviewed by kandi - BETA
                                                                                  kandi's functional review helps you automatically verify the functionalities of the libraries and avoid rework.
                                                                                  Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here
                                                                                  Get all kandi verified functions for this library.
                                                                                  Get all kandi verified functions for this library.

                                                                                  architecture-samples Key Features

                                                                                  A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.

                                                                                  architecture-samples Examples and Code Snippets

                                                                                  No Code Snippets are available at this moment for architecture-samples.
                                                                                  Community Discussions

                                                                                  Trending Discussions on architecture-samples

                                                                                  Why is there a object class defined within sealed class when I use Kotlin?
                                                                                  chevron right
                                                                                  Android Room Pre-populated Data not visible first time
                                                                                  chevron right
                                                                                  Why can't I write this particular assignment in Kotlin?
                                                                                  chevron right
                                                                                  Hilt Fragment has to be attached to @AndroidEntryPoint Activity, while testing (it is attached to @AndEntPoint marked activity)
                                                                                  chevron right
                                                                                  Android MVVM with servicelocator
                                                                                  chevron right
                                                                                  Why does a normal function need to be wrapped with viewModelScope.launch?
                                                                                  chevron right
                                                                                  Why does the author wrap tasksRepository.refreshTasks() with viewModelScope.launch?
                                                                                  chevron right
                                                                                  Android: Variable gets uninitialized in ViewModel after being initialized in the Fragment
                                                                                  chevron right
                                                                                  Can I replace _task.map with Transformations.map in Kotlin?
                                                                                  chevron right
                                                                                  How to mock the view model with Hilt for unit testing fragments?
                                                                                  chevron right

                                                                                  QUESTION

                                                                                  Why is there a object class defined within sealed class when I use Kotlin?
                                                                                  Asked 2022-Mar-25 at 00:45

                                                                                  The Code A is from the official sample project.

                                                                                  Result is a sealed class, I'm very strange why Loading is defined as object class.

                                                                                  I think the Code B is more reasonable, is it right?

                                                                                  Code A

                                                                                  sealed class Result {
                                                                                     data class Success(val data: T) : Result()
                                                                                     data class Error(val exception: Exception) : Result()
                                                                                     object Loading : Result()
                                                                                  
                                                                                     override fun toString(): String {
                                                                                        return when (this) {
                                                                                           is Success<*> -> "Success[data=$data]"
                                                                                           is Error -> "Error[exception=$exception]"
                                                                                           Loading -> "Loading"
                                                                                        }
                                                                                     }
                                                                                  }
                                                                                  

                                                                                  Code B

                                                                                  sealed class Result {
                                                                                     data class Success(val data: T) : Result()
                                                                                     data class Error(val exception: Exception) : Result()
                                                                                     data class Loading : Result()
                                                                                  
                                                                                     override fun toString(): String {
                                                                                        return when (this) {
                                                                                           is Success<*> -> "Success[data=$data]"
                                                                                           is Error -> "Error[exception=$exception]"
                                                                                           is Loading -> "Loading"
                                                                                        }
                                                                                     }
                                                                                  }
                                                                                  

                                                                                  Added Content:

                                                                                  To Tenfour04 and a_local_nobody: Thanks!

                                                                                  The Android Studio can compile and run after I add is before Loading -> "Loading" in Code C.

                                                                                  1: What are differents between Code A and Code C?

                                                                                  2: And more, In my mind, all types whithin sealed class should be the same, maybe they are all data class, or they are all object. But Code A mix data class and object, and it's Ok, does it mean that I add even Interface whithin sealed class ?

                                                                                  Code C

                                                                                  sealed class Result {
                                                                                     data class Success(val data: T) : Result()
                                                                                     data class Error(val exception: Exception) : Result()
                                                                                     object Loading : Result()
                                                                                  
                                                                                     override fun toString(): String {
                                                                                        return when (this) {
                                                                                           is Success<*> -> "Success[data=$data]"
                                                                                           is Error -> "Error[exception=$exception]"
                                                                                           is Loading -> "Loading"     // I add "is"
                                                                                        }
                                                                                     }
                                                                                  }
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2022-Mar-24 at 11:20

                                                                                  that won't work, because:

                                                                                  data class Loading : Result() <-- this isn't valid for a data class
                                                                                  

                                                                                  Data classes must have at least one primary constructor parameter, presumably the author used an object there to avoid having to make use of a constructor value, compared to the others:

                                                                                   data class Success(val data: T) : Result() <-- (val data: T)
                                                                                   data class Error(val exception: Exception) : Result() <-- (val exception: Exception)
                                                                                  

                                                                                  which clearly require values

                                                                                  Source https://stackoverflow.com/questions/71601256

                                                                                  QUESTION

                                                                                  Android Room Pre-populated Data not visible first time
                                                                                  Asked 2022-Feb-26 at 16:08

                                                                                  Freshly installing the app, the view model doesn't bind the data. Closing the app and opening it again shows the data on the screen.

                                                                                  Is there any problem with the pre-population of data or is the use of coroutine is not correct?

                                                                                  If I use Flow in place of LiveData, it collects the data on the go and works completely fine, but its a bit slow as it is emitting data in the stream.

                                                                                  Also, for testing, The data didn't load either LiveData/Flow. Tried adding the EspressoIdlingResource and IdlingResourcesForDataBinding as given here

                                                                                  Room creation
                                                                                    @Provides
                                                                                    @Singleton
                                                                                    fun provideAppDatabase(
                                                                                      @ApplicationContext context: Context,
                                                                                      callback: AppDatabaseCallback
                                                                                    ): AppDatabase {
                                                                                      return Room
                                                                                        .databaseBuilder(context, AppDatabase::class.java, "database_name")
                                                                                        .addCallback(callback)
                                                                                        .build()
                                                                                  
                                                                                  AppDatabaseCallback.kt
                                                                                   override fun onCreate(db: SupportSQLiteDatabase) {
                                                                                      super.onCreate(db)
                                                                                  
                                                                                      CoroutineScope(Dispatchers.IO).launch {
                                                                                        val data = computePrepopulateData(assets_file_name)
                                                                                        data.forEach { user ->
                                                                                          dao.get().insert(user)
                                                                                        }
                                                                                      }
                                                                                    }
                                                                                  
                                                                                  Dao
                                                                                  @Insert(onConflict = OnConflictStrategy.REPLACE)
                                                                                    suspend fun insertUser(user: User)
                                                                                  
                                                                                  @Query("SELECT * FROM $table_name")
                                                                                    suspend fun getAllUser(): List
                                                                                  
                                                                                  ViewModel
                                                                                  CoroutineScope(Dispatchers.IO).launch {
                                                                                        repository.getData().let {
                                                                                          listUser.postValue(it)
                                                                                        }
                                                                                      }
                                                                                  
                                                                                  Attaching the data using BindingAdapter
                                                                                  app:list="@{viewModel.listUser}"
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2022-Feb-26 at 16:08

                                                                                  Your DAO returns suspend fun getAllUser(): List, meaning it's a one time thing. So when the app starts the first time, the DB initialization is not complete, and you get an empty list because the DB is empty. Running the app the second time, the initialization is complete so you get the data.

                                                                                  How to fix it:

                                                                                  1. Switch getAllUser() to return a Flow:
                                                                                  // annotations omitted
                                                                                  fun getAllUser(): Flow>
                                                                                  
                                                                                  1. Switch insertUser to use a List
                                                                                  // annotations omitted
                                                                                  suspend fun insertUser(users: List)
                                                                                  

                                                                                  The reason for this change is reducing the number of times the Flow will emit. Every time the DB changes, the Flow will emit a new list. By inserting a List instead of inserting a single User many times the (on the first run) Flow will emit twice (an empty list + the full list) compared to number of user times with a single insert.

                                                                                  Another way to solve this issue is to use a transaction + insert a single user.

                                                                                  1. I recommend you use viewModelScope inside the ViewModel to launch coroutines so it's properly canceled when the ViewModel is destroyed.

                                                                                  Source https://stackoverflow.com/questions/71251832

                                                                                  QUESTION

                                                                                  Why can't I write this particular assignment in Kotlin?
                                                                                  Asked 2021-Jun-24 at 13:42

                                                                                  I'm using the MVI pattern in a project so I wrote both State and Event classes. For the Event part inside the viewModel I'm using a private property _event of type MutableLiveData, and exposing it to the Activity as a LiveData, this way:

                                                                                  private val _event = MutableLiveData()
                                                                                  val event: LiveData
                                                                                      get() {
                                                                                          return _event
                                                                                      }
                                                                                  
                                                                                  

                                                                                  Everything worked well until I needed to use the SingleLiveEvent class (instead of its supertype MutableLiveData) found in this sample code from Google; the SingleLiveEvent class extends MutableLiveData which in turn extends LiveData.

                                                                                  So I thought that I could write something like this:

                                                                                  private val _event: LiveData = SingleLiveEvent()
                                                                                  val event: LiveData
                                                                                      get() {
                                                                                          return _event
                                                                                      }
                                                                                  

                                                                                  But i get this error in the editor:

                                                                                  Type mismatch. Required: LiveData Found: SingleLiveEvent

                                                                                  What am I missing? SingleLiveEvent is a subtype of LiveData and it has the same type parameter, so why won't this assignment work?

                                                                                  Thanks in advance

                                                                                  ANSWER

                                                                                  Answered 2021-Jun-24 at 13:42

                                                                                  Not 100% sure, but I would bet you auto-converted the SingleLiveEvent Java code to Kotlin, and it declared it as a subclass of MutableLiveData instead of MutableLiveData.

                                                                                  Source https://stackoverflow.com/questions/68116810

                                                                                  QUESTION

                                                                                  Hilt Fragment has to be attached to @AndroidEntryPoint Activity, while testing (it is attached to @AndEntPoint marked activity)
                                                                                  Asked 2021-Mar-24 at 08:05

                                                                                  I followed a lot of tutorials/ articles and the googles architecture sample

                                                                                  No matter what I try I keep getting an error saying that I need to attach Fragment to @AndroidEntryPoint annotated Activity. I've setup everything correctly but still can't get this to work properly.

                                                                                  java.lang.IllegalStateException: Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: class com.nikolam.colorme.HiltTestActivity
                                                                                      at dagger.hilt.internal.Preconditions.checkState(Preconditions.java:83)
                                                                                      at dagger.hilt.android.internal.managers.FragmentComponentManager.createComponent(FragmentComponentManager.java:75)
                                                                                      at dagger.hilt.android.internal.managers.FragmentComponentManager.generatedComponent(FragmentComponentManager.java:64)
                                                                                      at com.nikolam.main_feature.presenter.main_screen.Hilt_MainFragment.generatedComponent(Hilt_MainFragment.java:80)
                                                                                      at com.nikolam.main_feature.presenter.main_screen.Hilt_MainFragment.inject(Hilt_MainFragment.java:102)
                                                                                      at com.nikolam.main_feature.presenter.main_screen.Hilt_MainFragment.initializeComponentContext(Hilt_MainFragment.java:63)
                                                                                      at com.nikolam.main_feature.presenter.main_screen.Hilt_MainFragment.onAttach(Hilt_MainFragment.java:55)
                                                                                      at androidx.fragment.app.Fragment.onAttach(Fragment.java:1783)
                                                                                      at com.nikolam.main_feature.presenter.main_screen.Hilt_MainFragment.onAttach(Hilt_MainFragment.java:45)
                                                                                      at androidx.fragment.app.Fragment.performAttach(Fragment.java:2911)
                                                                                      at androidx.fragment.app.FragmentStateManager.attach(FragmentStateManager.java:464)
                                                                                      at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:275)
                                                                                      at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
                                                                                      at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
                                                                                      at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1971)
                                                                                      at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:305)
                                                                                      at com.nikolam.colorme.main_feature.MainFragmentTest$whenMainActivityLaunchedNavigatorIsInvokedForFragment$$inlined$launchFragmentInHiltContainer$1.perform(HiltExt.kt:46)
                                                                                      at androidx.test.core.app.ActivityScenario.lambda$onActivity$2$ActivityScenario(ActivityScenario.java:660)
                                                                                      at androidx.test.core.app.ActivityScenario$$Lambda$4.run(Unknown Source)
                                                                                      at androidx.test.core.app.ActivityScenario.onActivity(ActivityScenario.java:670)
                                                                                      at com.nikolam.colorme.main_feature.MainFragmentTest.whenMainActivityLaunchedNavigatorIsInvokedForFragment(MainFragmentTest.kt:85)
                                                                                      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
                                                                                      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
                                                                                      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
                                                                                      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
                                                                                      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
                                                                                      at dagger.hilt.android.internal.testing.MarkThatRulesRanRule$1.evaluate(MarkThatRulesRanRule.java:106)
                                                                                      at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
                                                                                      at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:575)
                                                                                      at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:263)
                                                                                      at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
                                                                                      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                                                                                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                                                                                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                                                                                      at java.lang.Thread.run(Thread.java:748)
                                                                                  

                                                                                  Now here is my setup.

                                                                                  Dependencies

                                                                                      testImplementation(TestLibraryDependency.HILT_ANDROID_TESTING)
                                                                                      kaptTest(TestLibraryDependency.HILT_ANDROID_TESTING_COMPILER)
                                                                                      testImplementation(TestLibraryDependency.TEST_RUNNER)
                                                                                      testImplementation(TestLibraryDependency.ESPRESSO_CORE)
                                                                                      testImplementation(TestLibraryDependency.ANDROIDX_TEST_RULES)
                                                                                      testImplementation(TestLibraryDependency.ANDROIDX_CORE_TESTING)
                                                                                      testImplementation(TestLibraryDependency.ANDROIDX_TEST_EXT)
                                                                                  

                                                                                  This is my test

                                                                                  @HiltAndroidTest
                                                                                  @Config(application = HiltTestApplication::class, maxSdk = Build.VERSION_CODES.P)
                                                                                  @RunWith(RobolectricTestRunner::class)
                                                                                  class MainFragmentTest {
                                                                                  
                                                                                      @get:Rule()
                                                                                      var hiltAndroidRule = HiltAndroidRule(this)
                                                                                  
                                                                                      @Before
                                                                                      fun init() {
                                                                                          hiltAndroidRule.inject()
                                                                                      }
                                                                                  
                                                                                      @Test
                                                                                      fun whenMainActivityLaunchedNavigatorIsInvokedForFragment() {
                                                                                       //   launchActivity()
                                                                                          // GIVEN - On the home screen
                                                                                          val navController = mock(NavController::class.java)
                                                                                  
                                                                                          var fragment = launchFragmentInHiltContainer() {
                                                                                              Navigation.setViewNavController(this.view!!, navController)
                                                                                          }
                                                                                  
                                                                                          // WHEN - Click on the "+" button
                                                                                          onView(withId(R.id.add_floating_action)).perform(ViewActions.click())
                                                                                  
                                                                                          // THEN - Verify that we navigate to the add screen
                                                                                          verify(navController).navigate(
                                                                                              Uri.parse(UPLOAD_DEEPLINK)
                                                                                          )
                                                                                      }
                                                                                  
                                                                                  inline fun  launchFragmentInHiltContainer(
                                                                                      fragmentArgs: Bundle? = null,
                                                                                      @StyleRes themeResId: Int = R.style.FragmentScenarioEmptyFragmentActivityTheme,
                                                                                      crossinline action: Fragment.() -> Unit = {}
                                                                                  ) {
                                                                                      val startActivityIntent = Intent.makeMainActivity(
                                                                                          ComponentName(
                                                                                              ApplicationProvider.getApplicationContext(),
                                                                                              HiltTestActivity::class.java
                                                                                          )
                                                                                      ).putExtra(EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY, themeResId)
                                                                                  
                                                                                      ActivityScenario.launch(startActivityIntent).onActivity { activity ->
                                                                                          val fragment: Fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
                                                                                              Preconditions.checkNotNull(T::class.java.classLoader),
                                                                                              T::class.java.name
                                                                                          )
                                                                                          fragment.arguments = fragmentArgs
                                                                                          activity.supportFragmentManager
                                                                                              .beginTransaction()
                                                                                              .add(android.R.id.content, fragment, "")
                                                                                              .commitNow()
                                                                                  
                                                                                          fragment.action()
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  (I also have their custom runner)

                                                                                  I also have a debug source set that contains HiltTestActivity like here, alongside debug manifest.

                                                                                  Besides this, I'd like to somehow inject and initialize my NavigationManager (wrapper class around navController) in my Activity. Is there a way to achieve this? When I tried to use my MainActivity for tests I kept getting errors because my lateinit @Injects weren't getting initialized...

                                                                                  @AndroidEntryPoint
                                                                                  class MainActivity : AppCompatActivity() {
                                                                                  
                                                                                      private lateinit var binding: ActivityMainBinding;
                                                                                  
                                                                                      private lateinit var navController : NavController
                                                                                      @Inject
                                                                                      lateinit var navManager: NavManager
                                                                                  
                                                                                      private fun initNavManager() {
                                                                                          navManager.setOnNavEvent {
                                                                                              navController.navigate(it)
                                                                                          }
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2021-Mar-24 at 08:05

                                                                                  In my case I had to use

                                                                                      hilt {
                                                                                          enableTransformForLocalTests = true
                                                                                      }
                                                                                  

                                                                                  Since the Roboelectric/ Hilt has 20 bugs currently being tracked it was hard to pinpoint what workaround was the case :)

                                                                                  Source https://stackoverflow.com/questions/66764260

                                                                                  QUESTION

                                                                                  Android MVVM with servicelocator
                                                                                  Asked 2020-Dec-20 at 15:46

                                                                                  Im trying to make mvvm pattern with repository and servicelocator to use mock's or remote calls, it depends on flavour. What happening now,is that my liveData is not updating after i receive response from server. So for now i always have a empty list.

                                                                                  I use this google sample to trying make it. sample

                                                                                  My code below, using remote serviceLocator Appreciate your help.

                                                                                  class TestActivity : AppCompatActivity(){
                                                                                  
                                                                                  private val viewModel = TestViewModel(ServiceLocator.provideTasksRepository())
                                                                                  private lateinit var  binding : TestBinding
                                                                                  
                                                                                  override fun onCreate(savedInstanceState: Bundle?) {
                                                                                      super.onCreate(savedInstanceState)
                                                                                      binding = DataBindingUtil.setContentView(this, R.layout.test)
                                                                                      binding.viewmodel = viewModel
                                                                                  
                                                                                      setupRecyclerView()
                                                                                  }
                                                                                  
                                                                                  private fun setupRecyclerView() {
                                                                                      binding.viewmodel?.run {
                                                                                          binding.recyclerViewTest.adapter = TestAdapter(this)
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  }

                                                                                  class TestAdapter(private val viewModel : TestViewModel) : ListAdapter(TestDiffCallback()) {
                                                                                  
                                                                                  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = TestViewHolder.from(parent)
                                                                                  
                                                                                  override fun onBindViewHolder(holder: TestViewHolder, position: Int) {
                                                                                      val item = getItem(position)
                                                                                      holder.bind(viewModel, item)
                                                                                  }
                                                                                  
                                                                                  class TestViewHolder private constructor(val binding: ItemTestBinding) :
                                                                                      RecyclerView.ViewHolder(binding.root) {
                                                                                  
                                                                                      fun bind(viewModel: TestViewModel, item: ResponseEntity) {
                                                                                  
                                                                                          binding.viewmodel = viewModel
                                                                                          binding.game = item
                                                                                          binding.executePendingBindings()
                                                                                      }
                                                                                  
                                                                                      companion object {
                                                                                          fun from(parent: ViewGroup): TestViewHolder {
                                                                                              val layoutInflater = LayoutInflater.from(parent.context)
                                                                                              val binding = ItemTestBinding.inflate(layoutInflater, parent, false)
                                                                                  
                                                                                              return TestViewHolder(binding)
                                                                                          }
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  }

                                                                                  
                                                                                  

                                                                                  
                                                                                  
                                                                                      
                                                                                  
                                                                                      
                                                                                  
                                                                                      
                                                                                  
                                                                                      
                                                                                  
                                                                                  
                                                                                  
                                                                                  
                                                                                  
                                                                                      
                                                                                  
                                                                                  
                                                                                  
                                                                                  class MyRepository(private val testRemoteDataSource: IDataSource) :
                                                                                  ITestRepository {
                                                                                  
                                                                                  override suspend fun getList() = testRemoteDataSource.getList()
                                                                                  

                                                                                  }

                                                                                  class TestViewModel(private val testRepository: MyRepository) : ViewModel() {
                                                                                  
                                                                                  private var _items = MutableLiveData>()
                                                                                  val items: LiveData> = _items
                                                                                  
                                                                                  init {
                                                                                      refreshList()
                                                                                  }
                                                                                  
                                                                                  private fun refreshList() {
                                                                                      viewModelScope.launch {
                                                                                          _items = testRepository.getList()
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  }

                                                                                  object ServiceLocator {
                                                                                  
                                                                                  var testRepository: MyRepository? = null
                                                                                  
                                                                                  fun provideTasksRepository(): MyRepository {
                                                                                      synchronized(this) {
                                                                                          return testRepository ?: createTestRepository()
                                                                                      }
                                                                                  }
                                                                                  
                                                                                  private fun createTestRepository(): MyRepository {
                                                                                      val newRepo = MyRepository(
                                                                                          MyRemoteDataSource(RetrofitClient.apiInterface)
                                                                                      )
                                                                                      testRepository = newRepo
                                                                                      return newRepo
                                                                                  }
                                                                                  

                                                                                  }

                                                                                  class MyRemoteDataSource(private val retroService: IService) :
                                                                                  IDataSource {
                                                                                  
                                                                                  private var responseEntityLiveData: MutableLiveData> =
                                                                                      MutableLiveData>()
                                                                                  
                                                                                  override suspend fun getGames(): MutableLiveData> {
                                                                                  
                                                                                      retroService.getList()
                                                                                          .enqueue(object : Callback> {
                                                                                              override fun onFailure(
                                                                                                  call: Call>,
                                                                                                  t: Throwable
                                                                                              ) {
                                                                                                  responseEntityLiveData.value = emptyList()
                                                                                              }
                                                                                  
                                                                                              override fun onResponse(
                                                                                                  call: Call>,
                                                                                                  response: Response>
                                                                                              ) {
                                                                                                  responseEntityLiveData.value = response.body()
                                                                                              }
                                                                                          })
                                                                                  
                                                                                      return responseEntityLiveData
                                                                                  }
                                                                                  

                                                                                  }

                                                                                  ANSWER

                                                                                  Answered 2020-Dec-20 at 15:46

                                                                                  My guess is that mixing Coroutines suspending function with Retrofit and LiveData leads to some side effect here.

                                                                                  I do not have a single solution, but some points they can help you.

                                                                                  In general I would avoid mixing LiveData with suspending functions. LiveData is concept of caching data for the UI/ViewModel layer. Lower layers do not need to know anything like Android concrete stuff like LiveData. More information here

                                                                                  In your repository or dataSource can either use a suspending function that returns a single value or Coroutines Flow that can emit more than one value. In your ViewModel you can then map those results to your LiveData.

                                                                                  DataSource

                                                                                  In your DataSource you can use suspendCoroutine or suspendCancellableCoroutine to connect Retrofit (or any other callback interface) with Coroutines:

                                                                                  class DataSource(privat val retrofitService: RetrofitService) {
                                                                                  
                                                                                      /**
                                                                                       * Consider [Value] as a type placeholder for this example
                                                                                       */
                                                                                      fun suspend fun getValue(): Result = suspendCoroutine { continuation ->
                                                                                        retrofitService.getValue().enqueue(object : Callback {
                                                                                          override fun onFailure(call: Call>,
                                                                                                                 throwable: Throwable) {
                                                                                            continuation.resume(Result.Failure(throwable)))
                                                                                          }
                                                                                  
                                                                                          override fun onResponse(call: Call>,
                                                                                                                  response: Response>) {
                                                                                            continuation.resume(Result.Success(response.body()))
                                                                                          }
                                                                                        }
                                                                                     }
                                                                                  }
                                                                                  

                                                                                  Result Wrapper

                                                                                  You can wrap the response to your own Result type like:

                                                                                  sealed class Result {
                                                                                  
                                                                                      /**
                                                                                       * Indicates a success state.
                                                                                       */
                                                                                      data class Success(val data: T) : Result()
                                                                                  
                                                                                      /**
                                                                                       * Indicates an error state.
                                                                                       */
                                                                                      data class Failure(val throwable: Throwable): Result
                                                                                  }
                                                                                  

                                                                                  I leave the Repository out from this example and call directly the DataSource.

                                                                                  ViewModel

                                                                                  Now in your ViewModel you can launch the coroutine, getting the Result and map it to the LiveData.

                                                                                  class TestViewModel(private val dataSource: DataSource) : ViewModel() {
                                                                                      private val _value = MutableLiveData>()
                                                                                      val value: LiveData = _value
                                                                                  
                                                                                      private val _error = MutableLiveData()
                                                                                      val error: LiveData = _error
                                                                                  
                                                                                      init {
                                                                                          getValue()
                                                                                      }
                                                                                  
                                                                                      private fun getValue() {
                                                                                        viewModelScope.launch {
                                                                                          val result: Result = dataSource.getValue()
                                                                                          
                                                                                          // check wether the result is of type Success or Failure
                                                                                          when(result) {
                                                                                            is Result.Success -> _value.postValue(result.data)
                                                                                            is Result.Failure -> _error.value = throwable.message
                                                                                          }
                                                                                        }
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  I hope that helps you a bit.

                                                                                  Source https://stackoverflow.com/questions/65379854

                                                                                  QUESTION

                                                                                  Why does a normal function need to be wrapped with viewModelScope.launch?
                                                                                  Asked 2020-Oct-06 at 12:41

                                                                                  The following code is from the project.

                                                                                  1: In my mind,a suspend fun should be launched in another suspend fun or viewModelScope.launch{ }, withContext{ } ... , filterItems() is only a normal function, I don't know why filterItems() need to be wrapped with viewModelScope.launch{ } in the function filterTasks(), could you tell me ?

                                                                                  2: In the function filterTasks(), viewModelScope.launch{ } will launch in coroutines, it's asynchronous, I think return result maybe be launched before I get the result from viewModelScope.launch{}, so the result maybe null, is the code correct?

                                                                                  Code

                                                                                     private fun filterTasks(tasksResult: Result>): LiveData> {       
                                                                                          val result = MutableLiveData>()
                                                                                  
                                                                                          if (tasksResult is Success) {
                                                                                              isDataLoadingError.value = false
                                                                                              viewModelScope.launch {
                                                                                                  result.value = filterItems(tasksResult.data, getSavedFilterType())
                                                                                                  //return filterItems(tasksResult.data, getSavedFilterType())  //It will cause error.
                                                                                              }
                                                                                          } else {
                                                                                              result.value = emptyList()
                                                                                              showSnackbarMessage(R.string.loading_tasks_error)
                                                                                              isDataLoadingError.value = true
                                                                                          }
                                                                                  
                                                                                          return result //I think it maybe be launched before I get the result from viewModelScope.launch{}
                                                                                      }
                                                                                  
                                                                                  
                                                                                      private fun filterItems(tasks: List, filteringType: TasksFilterType): List {
                                                                                          val tasksToShow = ArrayList()
                                                                                          // We filter the tasks based on the requestType
                                                                                          for (task in tasks) {
                                                                                              when (filteringType) {
                                                                                                  ALL_TASKS -> tasksToShow.add(task)
                                                                                                  ACTIVE_TASKS -> if (task.isActive) {
                                                                                                      tasksToShow.add(task)
                                                                                                  }
                                                                                                  COMPLETED_TASKS -> if (task.isCompleted) {
                                                                                                      tasksToShow.add(task)
                                                                                                  }
                                                                                              }
                                                                                          }
                                                                                          return tasksToShow
                                                                                      }
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2020-Sep-16 at 22:26

                                                                                  yes, you are right. but if you looked up the implementation of the launch {} such in lifecycleScope.launch {} or viewModelScope.launch {} you would find out the "block" which is "the coroutine code which will be invoked in the context of the provided scope" is cast to be suspend, so any block of code between launch {} is suspend code block. so in your example filterItems is cast to suspend under the hood and it's wrapped with viewModelScope.launch{ } to do its heavy task not in main thread.

                                                                                  public fun CoroutineScope.launch(
                                                                                      context: CoroutineContext = EmptyCoroutineContext,
                                                                                      start: CoroutineStart = CoroutineStart.DEFAULT,
                                                                                      // the below line is doing the magic
                                                                                      block: suspend CoroutineScope.() -> Unit
                                                                                  ): Job {
                                                                                      val newContext = newCoroutineContext(context)
                                                                                      val coroutine = if (start.isLazy)
                                                                                          LazyStandaloneCoroutine(newContext, block) else
                                                                                          StandaloneCoroutine(newContext, active = true)
                                                                                      coroutine.start(start, coroutine, block)
                                                                                      return coroutine
                                                                                  }
                                                                                  

                                                                                  Source https://stackoverflow.com/questions/63788552

                                                                                  QUESTION

                                                                                  Why does the author wrap tasksRepository.refreshTasks() with viewModelScope.launch?
                                                                                  Asked 2020-Sep-11 at 02:57

                                                                                  The following code is from the project.

                                                                                  The function of tasksRepository.refreshTasks() is to insert data from remote server to local DB, it's a time consuming operation.

                                                                                  In class TasksViewModel, asksRepository.refreshTasks() is wrapped with viewModelScope.launch{}, it means launch and careless.

                                                                                  1: How can I guarantee tasksRepository.observeTasks().distinctUntilChanged().switchMap { filterTasks(it) } to return the latest result?

                                                                                  2: I don't know how distinctUntilChanged() work, will it keep listening to return the latest result in whole Lifecycle ?

                                                                                  3: What's happened if I use tasksRepository.observeTasks().switchMap { filterTasks(it) } instead of tasksRepository.observeTasks().distinctUntilChanged().switchMap { filterTasks(it) }

                                                                                  Code

                                                                                  class TasksViewModel(..) : ViewModel() {    
                                                                                      private val _items: LiveData> = _forceUpdate.switchMap { forceUpdate ->
                                                                                          if (forceUpdate) {
                                                                                              _dataLoading.value = true
                                                                                              viewModelScope.launch {
                                                                                                  tasksRepository.refreshTasks()
                                                                                                  _dataLoading.value = false
                                                                                              }
                                                                                          }
                                                                                          tasksRepository.observeTasks().distinctUntilChanged().switchMap { filterTasks(it) }
                                                                                      }
                                                                                     
                                                                                     ...
                                                                                  }
                                                                                  
                                                                                  
                                                                                  class DefaultTasksRepository(...) : TasksRepository {  
                                                                                  
                                                                                      override suspend fun refreshTask(taskId: String) {
                                                                                          updateTaskFromRemoteDataSource(taskId)
                                                                                      }
                                                                                  
                                                                                      private suspend fun updateTasksFromRemoteDataSource() {
                                                                                          val remoteTasks = tasksRemoteDataSource.getTasks()
                                                                                  
                                                                                          if (remoteTasks is Success) {
                                                                                              tasksLocalDataSource.deleteAllTasks()
                                                                                              remoteTasks.data.forEach { task ->
                                                                                                  tasksLocalDataSource.saveTask(task)
                                                                                              }
                                                                                          } else if (remoteTasks is Result.Error) {
                                                                                              throw remoteTasks.exception
                                                                                          }
                                                                                      }
                                                                                  
                                                                                      override fun observeTasks(): LiveData>> {
                                                                                          return tasksLocalDataSource.observeTasks()
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2020-Sep-11 at 02:57
                                                                                  1. switchMap - The returned LiveData delegates to the most recent LiveData created by calling switchMapFunction with the most recent value set to source, without changing the reference. Doc

                                                                                  2. Yes, it'll keep listening to return the latest result in whole Lifecycle. distinctUntilChanged creates a new LiveData object that does not emit a value until the source LiveData value has been changed. The value is considered changed if equals() yields false.

                                                                                  3. Yes you can use that too but it'll keep emitting the values even the values are the same as the last emitted value. e.g. first emitted value is ["aman","bansal"] and the second is the same ["aman","bansal"] which you don't want to emit since the values are same. So you use distinctUntilChanged to make sure it won't emit the same value until changed.

                                                                                  I hope this helped.

                                                                                  Source https://stackoverflow.com/questions/63786499

                                                                                  QUESTION

                                                                                  Android: Variable gets uninitialized in ViewModel after being initialized in the Fragment
                                                                                  Asked 2020-Sep-08 at 07:41

                                                                                  I have a callback method in my fragment which gets called from it's ViewModel. It initializes the variable in the OnCreateView() method of the fragment, but when the ViewModel calls it to use it, its null.

                                                                                  I am thinking that it has something to do with maybe the VM getting recreated somehow? I just can't seem to figure it out.

                                                                                  I am following this answer's of how the VM drives the UI. They provide Google's sample of a callback interface being created (TasksNavigator.java), Overriding the method in the View (TasksActivity.java), and then calling that method from the VM (TasksViewModel.java) but it doesn't seem to work for me.

                                                                                  Fragment

                                                                                  class SearchMovieFragment : Fragment(), SearchNavigator {
                                                                                  
                                                                                      companion object {
                                                                                          fun newInstance() = SearchMovieFragment()
                                                                                      }
                                                                                  
                                                                                      private lateinit var searchMovieFragmentViewModel: SearchMovieFragmentViewModel
                                                                                      private lateinit var binding: SearchMovieFragmentBinding
                                                                                      private lateinit var movieRecyclerView: RecyclerView
                                                                                  
                                                                                      override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
                                                                                  
                                                                                          searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
                                                                                          binding = DataBindingUtil.inflate(inflater, R.layout.search_movie_fragment, container, false)
                                                                                          binding.viewmodel = searchMovieFragmentViewModel
                                                                                          searchMovieFragmentViewModel.setNavigator(this)
                                                                                  
                                                                                          setUpRecyclerView(container!!.context)
                                                                                          return binding.root
                                                                                      }
                                                                                  
                                                                                      private fun setUpRecyclerView(context: Context) {
                                                                                          movieRecyclerView = binding.searchMovieFragmentRecyclerView.apply {
                                                                                              this.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
                                                                                          }
                                                                                          val adapter = MovieListAdapter()
                                                                                          binding.searchMovieFragmentRecyclerView.adapter = adapter
                                                                                          searchMovieFragmentViewModel.movieList.observe(viewLifecycleOwner, Observer {
                                                                                              adapter.submitList(it)
                                                                                          })
                                                                                      }
                                                                                  
                                                                                      override fun openDetails() {
                                                                                          Log.d("TEST", "opening details")
                                                                                      }
                                                                                  }
                                                                                  

                                                                                  ViewModel

                                                                                  
                                                                                  class SearchMovieFragmentViewModel : ViewModel(), MovieSearchItemViewModel {
                                                                                  
                                                                                      private lateinit var searchNavigator: SearchNavigator
                                                                                      val editTextContent = MutableLiveData()
                                                                                      var movieList = Repository.getMovieList("batman")
                                                                                  
                                                                                      fun setNavigator(_searchNavigator: SearchNavigator) {
                                                                                          this.searchNavigator = _searchNavigator
                                                                                          if (searchNavigator != null) {
                                                                                              Log.d("TEST", "its not null $searchNavigator") // Here it is not null
                                                                                          }
                                                                                      }
                                                                                  
                                                                                      private fun getMovieDetail(movieId: String) {
                                                                                          val movie = Repository.getMovieDetail(movieId)
                                                                                  
                                                                                          Log.d("TEST", "checking ${this.searchNavigator}") // Here is where I call it but it is null
                                                                                  //        searchNavigator.openDetails()
                                                                                      }
                                                                                      private fun getMovieList(movieSearch: String): MutableLiveData> = Repository.getMovieList(movieSearch)
                                                                                  
                                                                                      override fun displayMovieDetailsButton(movieId: String) {
                                                                                          Log.d("TEST", "button clicked $movieId")
                                                                                          getMovieDetail(movieId)
                                                                                      }
                                                                                  }
                                                                                  
                                                                                  

                                                                                  CallBack Interface

                                                                                  interface SearchNavigator {
                                                                                      fun openDetails()
                                                                                  }
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2020-Sep-08 at 07:04

                                                                                  Initiate ViewModel in below method of fragment

                                                                                  override onActivityCreated(@Nullable final Bundle savedInstanceState){
                                                                                      searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
                                                                                  }
                                                                                  

                                                                                  I will recommend use live data to create connection between ViewModel and and Fragment it will be safer and correct approach.

                                                                                  Trigger openDetails based on the trigger's from your live data.It's forbidden to send your view(context) instance to ViewModel even if you wrap it as there is high probability of memory leaks.

                                                                                  But if you still want to follow this approach then you should Register and unregister fragment instance in your ViewModel (keep a list of SearchNavigator) it onStop() and onStart() .

                                                                                  and loop through them to call openDetails

                                                                                  Source https://stackoverflow.com/questions/63788508

                                                                                  QUESTION

                                                                                  Can I replace _task.map with Transformations.map in Kotlin?
                                                                                  Asked 2020-Aug-25 at 07:33

                                                                                  The Code A is fom the project.

                                                                                  I think Code B is the same as Code A, right?

                                                                                  Code A

                                                                                  val task: LiveData = _task
                                                                                  val completed: LiveData = _task.map { input: Task? ->
                                                                                      input?.isCompleted ?: false
                                                                                  }
                                                                                  

                                                                                  Code B

                                                                                  val task: LiveData = _task
                                                                                  val completed =  Transformations.map(_task){input: Task? ->
                                                                                      input?.isCompleted ?: false
                                                                                  }
                                                                                  

                                                                                  ANSWER

                                                                                  Answered 2020-Aug-25 at 07:33

                                                                                  Yes, it is absolutely identical because LiveData.map is an extension function that provided from Transformations.kt file that is a part of dependency:

                                                                                  def lifecycle_version = "2.2.0"
                                                                                  implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
                                                                                  

                                                                                  This is what map extension function does which is absolutely identical to Code B:

                                                                                  inline fun  LiveData.map(crossinline transform: (X) -> Y): LiveData =
                                                                                          Transformations.map(this) { transform(it) }
                                                                                  

                                                                                  Source https://stackoverflow.com/questions/63571200

                                                                                  QUESTION

                                                                                  How to mock the view model with Hilt for unit testing fragments?
                                                                                  Asked 2020-Aug-12 at 20:39

                                                                                  I've got an android app setup for dependency injection using Hilt, and would like to unit test my fragments.

                                                                                  I'm currently creating my view model using:

                                                                                  private val viewModel: ExampleViewModel by viewModels()
                                                                                  

                                                                                  And I am creating the fragment for testing using the code from here

                                                                                  I need to replace this ExampleViewModel with a mock, how would I go about doing this?

                                                                                  ANSWER

                                                                                  Answered 2020-Aug-12 at 20:39

                                                                                  I will paste here the "danysantiago" response in a issue (https://github.com/google/dagger/issues/1972) related to your question:

                                                                                  Hilt ViewModel extension works by declaring modules that bind assisted factories to a map and not by binding concrete ViewModels. Therefore, what you want to do is bind the assisted factory of the concrete ViewModel using the key of the abstract ViewModel so that when HiltViewModelFactory looks up the factory based on class key it uses the assisted factory for the concrete ViewModel. This is suuuper obscure and hence why I mean not 'easily' available.

                                                                                  However, if you can expand on the test case your are trying to write that could help us provide some guidance, I'm not sure if you are trying to mock/fake the ViewModel itself for tests, but Hilt testing APIs should allow you to replace dependencies in the ViewModel so you can write a test with the Fragment and the ViewModel.

                                                                                  Source https://stackoverflow.com/questions/62823817

                                                                                  Community Discussions, Code Snippets contain sources that include Stack Exchange Network

                                                                                  Vulnerabilities

                                                                                  No vulnerabilities reported

                                                                                  Install architecture-samples

                                                                                  You can download it from GitHub.

                                                                                  Support

                                                                                  For any new features, suggestions and bugs create an issue on GitHub. If you have any questions check and ask questions on community page Stack Overflow .
                                                                                  Find more information at:
                                                                                  Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
                                                                                  Find more libraries
                                                                                  Explore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits​
                                                                                  Save this library and start creating your kit
                                                                                  CLONE
                                                                                • HTTPS

                                                                                  https://github.com/android/architecture-samples.git

                                                                                • CLI

                                                                                  gh repo clone android/architecture-samples

                                                                                • sshUrl

                                                                                  git@github.com:android/architecture-samples.git

                                                                                • Share this Page

                                                                                  share link

                                                                                  Explore Related Topics

                                                                                  Consider Popular Architecture Libraries

                                                                                  Try Top Libraries by android

                                                                                  sunflower

                                                                                  by androidKotlin

                                                                                  compose-samples

                                                                                  by androidKotlin

                                                                                  uamp

                                                                                  by androidKotlin

                                                                                  nowinandroid

                                                                                  by androidKotlin

                                                                                  Compare Architecture Libraries with Highest Support

                                                                                  Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
                                                                                  Find more libraries
                                                                                  Explore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits​
                                                                                  Save this library and start creating your kit