SlideShare a Scribd company logo
1 of 76
Download to read offline
KimKevin
Android Developer / Kakaobank
Android Jetpack

ViewModel and Testing
ViewModel
Model
Presenter
View
Repository
The past of past
Model
ViewModel

(Not AAC)
Presenter
Repository
View
Databinding
The past
Model
AAC ViewModel
Repository
View
Databinding
The present
ViewModel
! The Lifecycle Library’s ViewModel class

! android.arch.lifecycle -> androidx.lifecycle

! Provides data for UI components and survive configuration changes.
ViewModel can help
! Avoiding memory leaks

! Solving common Android lifecycle challenges
ViewModel can help
! Avoiding memory leaks

! Solving common Android lifecycle challenges

! Share data between fragments
class UserViewModel : ViewModel() {
val name = MutableLiveData<String>()
}
class UserFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
val userViewModel =
ViewModelProviders.of(getActivity()).get(UserViewModel::class.java)
loginButton.setOnClickListener({ item -> userViewModel.name = item })
}
}
class UserProfileFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
val userViewModel =
ViewModelProviders.of(getActivity()).get(UserViewModel::class.java)
userViewModel.name.observe(this, { name ->
// Update the UI.
})
}
}
ViewModel can help
! Avoiding memory leaks

! Solving common Android lifecycle challenges

! Share data between fragments

! Design good software (SRP, testing etc)
Activity
Activity
Data Loading
Drawing UI
Components
Processing Data
Handling all UI
Interactions
Saving and
restoring the UI
Data Loading
Drawing UI
Components
Processing Data
Handling all UI
Interactions
Saving and
restoring the UI
Activity
Activity
https://stackify.com/solid-design-principles
Data Loading
Drawing UI
Components
Processing Data
Handling all UI
Interactions
Saving and
restoring the UI
Activity
Activity
Single Responsibility Principle
https://stackify.com/solid-design-principles
Activity

Drawing UI

Receiving User Interactions
as Android Developer
Activity

Drawing UI

Receiving User Interactions
ViewModel

Hold UI Data
Repository

API for saving and loading app data
Presenter

Process data for UI
User Case

full fledged clean architecture
And more…
as Android Developer
as Java Developer
Activity

Drawing UI

Receiving User Interactions
ViewModel

Hold UI Data
Repository

API for saving and loading app data
Presenter

Process data for UI
User Case

full fledged clean architecture
And more…
as Android Developer
as Java Developer
Provides

APIs
Testable
Code
Reactive UI
! ViewModel

! LiveData

! Data Binding 

! Android Studio 3.1 +

! Support for ViewModel and LiveData

! setLifecycleOwner(LifecycleOwner)
ViewModel could do
! Handle configuration changes

! Replace onSaveInstanceState()
Activity Instance
Activity UI data
Activity Instance
RotationEvent
Activity UI data
Activity Instance
Recreated Activity

Instance
RotationEvent
Forgotten data that didn’t get passed to next activity
Activity UI data
<activity android:name="MainActivity"
android:configChanges="screenSize|orientation" />
Activity
Fragment
public void onCreate(@Nullable Bundle savedInstanceState) {
···
setRetainInstance(true)
}
ViewModel
Activity Instance
Activity UI data
ViewModel
Activity UI data
RotationEvent
Activity Instance
ViewModel
Activity UI data
Activity Instance
Recreated Activity

Instance
RotationEvent
class UserLoginViewModel : ViewModel() {
private val _id = MutableLiveData<String>()
val id: LiveData<String>
get() = _id
private val _password = MutableLiveData<String>()
val password: LiveData<String>
get() = _password
···
}
public abstract class ViewModel {
@SuppressWarnings("WeakerAccess")
protected void onCleared() { }
}
public abstract class ViewModel {
@SuppressWarnings("WeakerAccess")
protected void onCleared() { }
}
@Override
protected void onDestroy() {
super.onDestroy();
···
mViewModelStore.clear();
···
}
FragmentActivity & Fragment
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
@Override
protected void onDestroy() {
super.onDestroy();
···
mViewModelStore.clear();
···
}
FragmentActivity & Fragment
ViewModelStore
WARNING!
! Don’t store Contexts in a ViewModel

! Activities, Fragments, Views, etc
ViewModel
Activity UI data
Activity Instance
If you store an
Activity
ViewModel
Activity UI data
Activity Instance
If you store an
Activity
RotationEvent
ViewModel
Activity UI data
Activity Instance
If you store an
Activity
RotationEvent
Recreated Activity

Instance
MEMORY LEAK
override fun onCreate(savedInstanceState: Bundle?) {
···
val userLoginViewModel =
ViewModelProviders.of(this, factory).get(UserLoginViewModel::class.java)
}
ViewModelProdivers.of() creates a ViewModelProvider
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
override fun onCreate(savedInstanceState: Bundle?) {
···
val userLoginViewModel =
ViewModelProviders.of(this, factory).get(UserLoginViewModel::class.java)
}
ViewModelProviders
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
// Lifecycles 2.0.0-alpha1 (AndroidX)
return new ViewModelProvider(activity.getViewModelStore(), factory);
// Lifecycles 1.1.1
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
ViewModelProviders
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
public HolderFragment() {
setRetainInstance(true);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
···
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
ViewModelStores (Not included in AndroidX)
ViewModelProviders
Lifecycles 1.1.1
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
···
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
public static ViewModelProvider of(@NonNull Fragment fragment,
@Nullable Factory factory) {
···
return new ViewModelProvider(fragment.getViewModelStore(), factory);
}
// for FragmentActivity
Lifecycles 2.0.0-alpha1 (AndroidX)
ViewModelProviders
// for Fragment
ViewModelStore

ViewModel2
FragmentA

ViewModel3
ViewModelStore

ViewModel1
ViewModel1
FragmentB

ViewModel2
Created FragmentActivity
ViewModelStore

ViewModel2
FragmentA

ViewModel3
ViewModelStore

ViewModel1
FragmentB

Recreated FragmentActivity on rotation
ViewModelStore

ViewModel2
FragmentA

ViewModel3
ViewModelStore

ViewModel1
ViewModel1
ViewModelProvider
ViewModelProviders
FragmentB

ViewModel2
Restored ViewModels
ViewModelStore

ViewModel2
ViewModel3
ViewModelStore

ViewModel1
FragmentA

ViewModel1
ViewModelProvider
ViewModelProviders
FragmentB

ViewModel2
Restored ViewModels
ViewModelStore

ViewModel2
ViewModel3
ViewModelStore

ViewModel1
How to restore ViewModelStore
@Override
public final Object onRetainNonConfigurationInstance() {
···
Object custom = onRetainCustomNonConfigurationInstance();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
if (fragments == null && mViewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = mViewModelStore;
nci.fragments = fragments;
return nci;
}
FragmentActivity Retain All fragment state
FragmentActivity Restore All fragment state
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
···
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
···
}
FragmentActivity Restore All fragment state
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
···
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
mViewModelStore = nc.viewModelStore;
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
···
}
Restore All fragment state
public void restoreAllState(Parcelable state, FragmentManagerNonConfig
nonConfig) {
mHost.mFragmentManager.restoreAllState(state, nonConfig);
}
FragmentController
Restore All fragment state
FragmentController
public void restoreAllState(Parcelable state, FragmentManagerNonConfig
nonConfig) {
mHost.mFragmentManager.restoreAllState(state, nonConfig);
}
FragmentManager
void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
···
if (nonConfig != null) {
List<Fragment> nonConfigFragments = nonConfig.getFragments();
childNonConfigs = nonConfig.getChildNonConfigs();
viewModelStores = nonConfig.getViewModelStores();
···
mActive = new SparseArray<>(fms.mActive.length);
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
FragmentManagerNonConfig childNonConfig = null;
if (childNonConfigs != null && i < childNonConfigs.size()) {
childNonConfig = childNonConfigs.get(i);
}
ViewModelStore viewModelStore = null;
if (viewModelStores != null && i < viewModelStores.size()) {
viewModelStore = viewModelStores.get(i);
}
Fragment f = fs.instantiate(mHost, mContainer, mParent,
childNonConfig, viewModelStore);
Restore All fragment state
ViewModel could do
! Handle configuration changes?
ViewModel could do
! Handle configuration changes? Yes!
ViewModel could do
! Handle configuration changes? Yes!

! Replace onSaveInstanceState()?
ViewModel could do
! Handle configuration changes? Yes!

! Replace onSaveInstanceState()? No!
Use ViewModel with onSaveInstanceState
• Survives configuration changes

• Hold lots of data
• Survives configuration changes and process death

• Requires serialization

• Hold small amount of data (less than 50k of data)
All data for Activity UI
Data to reload Activity data

in emergency
ViewModel onSaveInstanceState
Use ViewModel with onSaveInstanceState
• Survives configuration changes

• Hold lots of data
• Survives configuration changes and process death

• Requires serialization

• Hold small amount of data (less than 50k of data)
All the user’s data:

User id, first name, last name, birthday,

address, profile images…
User id
ViewModel onSaveInstanceState
and Testing
https://github.com/mockito/mockito/issues/1013
Wiki & Docs
How to use Search feature
• Handling network errors
• ERROR CODE : 1003
• Do something!
•
•
Wiki & Docs
How to use Search feature
• Handling network errors
• ERROR CODE : 1003
• Do something!
•
•
Hard to keep document the latest,

whenever requirement changes
Why writing Unit tests
! Think of unit tests as documentation for future developers

! Help developers to refactor safely
https://www.shutterstock.com
Testing is 

not only for you

but also for your colleagues in your next seat
Presenter Testing
! Behavior Driven Testing

! Template : Given-When-Then (3A - Arrange-Act-Assert)
@Test
fun givenErrorCode1003_whenSearch_shouldHandleError() {
val networkError = NetworkException(1003, "Network Error!")
doThrow(networkError).when(mockSearchRepository).search(INVALID_QUERY)
presenter.search(INVALID_QUERY)
verify(view).hideLoading()
verify(view).setErrorMessage(networkError.message)
}
ViewModel Testing
! Assert data values
@Test
fun givenErrorCode1003_whenSearch_shouldHandleError() {
val networkError = NetworkException(1003, "Network Error!")
doThrow(networkError).when(mockSearchRepository).search(INVALID_QUERY)
presenter.search(INVALID_QUERY)
verify(view).hideLoading()
verify(view).setErrorMessage(networkError.message)
}
@Test
fun givenErrorCode1003_whenSearch_shouldHandleError() {
···
viewModel.search(INVALID_QUERY)
assertEquals(viewModel.loading.value, false)
assertEquals(viewModel.errorMessage.value, networkError.message)
}
Presenter
ViewModel
ViewModel Testing
! Assert data values

! Verify Observer onChanged() events

! Dependency for testing LiveData

! testImplementation “android.arch.core:core-testing:{version}“

! @Rule 

val instantTaskExecutorRule = InstantTaskExecutorRule()
@Test
fun givenErrorCode1003_whenSearch_shouldHandleError() {
···
val mockObserver = mock<Observer<Boolean>>()
viewModel.loading.observeForever(mockObserver)
viewModel.search(INVALID_QUERY)
assertEquals(viewModel.loading.value, false)
verify(mockObserver).onChanged(false)
}
class SearchActivity : AppCompatActivity() {
viewModel.loading.observe(this, Observer {
it?.let {
if (it) loading.visibility = View.VISIBLE
else loading.visibility = View.GONE
}
})
}
SearchActivity
Mockito features
! verify(), reset(), never(), doThrow()

! verifyNoMoreInteractions()

! verifyZeroInteractions()
@Test
fun givenErrorCode1003_whenSearch_shouldHandleError() {
···
val mockObserver = mock<Observer<Boolean>>()
viewModel.loading.observeForever(mockObserver)
viewModel.search(INVALID_QUERY)
verify(mockObserver).onChanged(false)
reset(mockObserver)
// For making sure interaction(s) never happened on mock
verifyNoMoreInteractions(mockObserver)
verify(mockObserver, never()).onChanged(any())
// For finding redundant invocations
verifyZeroInteractions(mockData1, mockData2)
}
Thank you
@imkimkevin / imkimkevin@gmail.com
Kevin Yongjun Kim
References
! https://www.youtube.com/watch?v=5qlIPTDE274
! https://medium.com/google-developers/viewmodels-persistence-
onsaveinstancestate-restoring-ui-state-and-loaders-fc7cc4a6c090
! https://developer.android.com/topic/libraries/architecture/viewmodel

More Related Content

What's hot

Spring 3: What's New
Spring 3: What's NewSpring 3: What's New
Spring 3: What's New
Ted Pennings
 
JQuery New Evolution
JQuery New EvolutionJQuery New Evolution
JQuery New Evolution
Allan Huang
 
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtArchitecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Alina Vilk
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 
important struts interview questions
important struts interview questionsimportant struts interview questions
important struts interview questions
surendray
 

What's hot (20)

Data binding в массы!
Data binding в массы!Data binding в массы!
Data binding в массы!
 
Wicket 6
Wicket 6Wicket 6
Wicket 6
 
iOS Talks 6: Unit Testing
iOS Talks 6: Unit TestingiOS Talks 6: Unit Testing
iOS Talks 6: Unit Testing
 
Android Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageAndroid Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, Vonage
 
Spring 3: What's New
Spring 3: What's NewSpring 3: What's New
Spring 3: What's New
 
Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019
 
JQuery New Evolution
JQuery New EvolutionJQuery New Evolution
JQuery New Evolution
 
Binding business data to vaadin components
Binding business data to vaadin componentsBinding business data to vaadin components
Binding business data to vaadin components
 
iBATIS
iBATISiBATIS
iBATIS
 
Code to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern ApplicationsCode to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern Applications
 
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtArchitecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
 
State management in android applications
State management in android applicationsState management in android applications
State management in android applications
 
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC BelgiquePrésentation et bonnes pratiques du pattern MVVM - MIC Belgique
Présentation et bonnes pratiques du pattern MVVM - MIC Belgique
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
Dialogs in Android MVVM (14.11.2019)
Dialogs in Android MVVM (14.11.2019)Dialogs in Android MVVM (14.11.2019)
Dialogs in Android MVVM (14.11.2019)
 
Smooth scrolling in UITableView and UICollectionView
Smooth scrolling in UITableView and UICollectionViewSmooth scrolling in UITableView and UICollectionView
Smooth scrolling in UITableView and UICollectionView
 
Accessing Data Through Hibernate; What DBAs Should Tell Developers and Vice V...
Accessing Data Through Hibernate; What DBAs Should Tell Developers and Vice V...Accessing Data Through Hibernate; What DBAs Should Tell Developers and Vice V...
Accessing Data Through Hibernate; What DBAs Should Tell Developers and Vice V...
 
important struts interview questions
important struts interview questionsimportant struts interview questions
important struts interview questions
 
What's new in Java EE 7
What's new in Java EE 7What's new in Java EE 7
What's new in Java EE 7
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 

Similar to Android Jetpack: ViewModel and Testing

Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
Eyal Vardi
 

Similar to Android Jetpack: ViewModel and Testing (20)

Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
 
Android architecture components - how they fit in good old architectural patt...
Android architecture components - how they fit in good old architectural patt...Android architecture components - how they fit in good old architectural patt...
Android architecture components - how they fit in good old architectural patt...
 
Backbone Basics with Examples
Backbone Basics with ExamplesBackbone Basics with Examples
Backbone Basics with Examples
 
[2019] 벅스 5.0 (feat. Kotlin, Jetpack)
[2019] 벅스 5.0 (feat. Kotlin, Jetpack)[2019] 벅스 5.0 (feat. Kotlin, Jetpack)
[2019] 벅스 5.0 (feat. Kotlin, Jetpack)
 
Android Architecture Components
Android Architecture ComponentsAndroid Architecture Components
Android Architecture Components
 
MVC pattern for widgets
MVC pattern for widgetsMVC pattern for widgets
MVC pattern for widgets
 
Optimize CollectionView Scrolling
Optimize CollectionView ScrollingOptimize CollectionView Scrolling
Optimize CollectionView Scrolling
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.js
 
Say bye to Fragments with Conductor & Kotlin
Say bye to Fragments with Conductor & KotlinSay bye to Fragments with Conductor & Kotlin
Say bye to Fragments with Conductor & Kotlin
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
Survive the lifecycle
Survive the lifecycleSurvive the lifecycle
Survive the lifecycle
 
MVVM Lights
MVVM LightsMVVM Lights
MVVM Lights
 
Android development with Scala and SBT
Android development with Scala and SBTAndroid development with Scala and SBT
Android development with Scala and SBT
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
Model viewviewmodel2
Model viewviewmodel2Model viewviewmodel2
Model viewviewmodel2
 
MVVM with Databinding and Google's new ViewModel. UA Mobile 2017.
MVVM with Databinding and Google's new ViewModel. UA Mobile 2017.MVVM with Databinding and Google's new ViewModel. UA Mobile 2017.
MVVM with Databinding and Google's new ViewModel. UA Mobile 2017.
 

More from Yongjun Kim

More from Yongjun Kim (6)

Android DataBinding (ViewModel, UI Modularization and Testing)
Android DataBinding (ViewModel, UI Modularization and Testing)Android DataBinding (ViewModel, UI Modularization and Testing)
Android DataBinding (ViewModel, UI Modularization and Testing)
 
Google I/O 2018: All of the News from Keynote
Google I/O 2018: All of the News from KeynoteGoogle I/O 2018: All of the News from Keynote
Google I/O 2018: All of the News from Keynote
 
Android Studio에서 vim사용과 오픈소스 ideavim 커스터마이징
Android Studio에서 vim사용과 오픈소스 ideavim 커스터마이징Android Studio에서 vim사용과 오픈소스 ideavim 커스터마이징
Android Studio에서 vim사용과 오픈소스 ideavim 커스터마이징
 
How to use vim in Android Studio, Useful customization IdeaVim
How to use vim in Android Studio, Useful customization IdeaVimHow to use vim in Android Studio, Useful customization IdeaVim
How to use vim in Android Studio, Useful customization IdeaVim
 
Where is CEO?
Where is CEO?Where is CEO?
Where is CEO?
 
플리토 코드리뷰 - Code Review in Flitto
플리토 코드리뷰 - Code Review in Flitto플리토 코드리뷰 - Code Review in Flitto
플리토 코드리뷰 - Code Review in Flitto
 

Recently uploaded

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Recently uploaded (20)

How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 

Android Jetpack: ViewModel and Testing