SlideShare a Scribd company logo
1 of 104
Download to read offline
Building complex
screens on
Android
Maciej Witowski
April 10th 2019, 1pm
Usability
#ZES19
Let’s get started!
Check-in to the session
on the App!
Turn on the Zoom! Record the Zoom!
#ZES19
A long time ago...
A long time ago...
A long time ago...
● One of the top mobile CRMs
in App Store and Play Store
● 8000 paying users
● Offline mode, Voice, Calendar, Maps etc.
● Average screen time at 71 minutes per day
With a lot of features comes a lot of responsibility
With a lot of features comes a lot of responsibility
many lines of code
> 400k LOC
This talk
Old vs New way of building screens
Main types of objects in Sell
Main types of objects in Sell
Contact
Company
Person
Lead
Deal
Main types of objects in Sell
Contact
Company
Person
Lead
Deal
Main types of objects in Sell
Contact
Company
Person
Lead
Deal
You can create new
objects and edit
existing ones
Our task
Build the edit screens for these objects
The Old Way
Types Edit Screens
Contact
Company
Person
Lead
Deal
Types Edit Screens
Contact
Company
Person
Lead
Deal
ContactEditFragment
CompanyEditFragment
PersonEditFragment
DealEditFragment
LeadEditFragment
Fragment per object type
● Huge classes containing both view and logic
● Deep inheritance hierarchy
● Duplicated functionality
BaseFragment
Fragment
ContactEditFragment
CompanyEditFragment
Callbacks everywhere
● No clear direction
● Confusing lifecycle
● Problematic events handling
● Errors propagation
@OnClick(R.id.show_company)
private void onClick() {
Loader<Company> loader = new Loader<Company>(){
@Override
public void onLoadFinished(Company company) {
setCompanyData(company);
}
};
initLoader(loader);
}
Mutable state
● Extreme complexity growth
● Hard to debug
● Concurrency problem
private ContactData initialContactData;
private ContactData currentContactData;
private ContactData temporaryContactData;
private boolean isErrorShown;
private boolean canSaveNow;
Coupling with Android SDK
● No boundary between business logic and platform code
● Handling quirky APIs
● No way to unit test
● Espresso not ready
Modeling with primitives
● No built-in support for value objects in Java
● Working with Android SDK
Modeling with primitives
● No built-in support for value objects in Java
● Working with Android SDK
● “Performance impact”
Old times - sum up
● Inheritance
● Callbacks
● Mutable state
● Coupling with the Android SDK
● Lack of tests
● Modeling the logic using primitives
Time went by...
Time went by...
● Building many new screens
● Exploring new patterns, mostly Model-View-Presenter
● New tools, Kotlin, RxJava, Espresso
Time went by...
● Building many new screens
● Exploring new patterns, mostly Model-View-Presenter
● New tools: Kotlin, RxJava, Espresso
When it comes to the edit screens
● Small product changes
● Didn’t justify the investment
● Sticking the new code and hoping it will work
2017: Required Fields
What is a better way to build screens?
Unidirectional Data Flow
StoreView
State
Actions
Unidirectional Data Flow
StoreView
State
https://github.com/zendesk/Suas-Android
Actions
Unidirectional Data Flow
View Reducer
Fields Builder
Configuration
Provider
Store
Unidirectional Data Flow
Unidirectional Data Flow
name: null,
phone: null
Unidirectional Data Flow
name: null,
phone: null
name: null,
phone: null
Unidirectional Data Flow
name: null,
phone: null
field(name: null),
field(phone: null)
name: null,
phone: null
Unidirectional Data Flow
name: null,
phone: null
field(name: null),
field(phone: null)
name: null,
phone: null
field(name: null),
field(phone: null)
Unidirectional Data Flow
field(name: null),
field(phone: null)
name: null,
phone: null
field(name: null),
field(phone: null)
name: null,
phone: null
Unidirectional Data Flow
field(name: null),
field(phone: null)
name: null,
phone: null
field(name: null),
field(phone: null)
name: null,
phone: null
name: “Joe”
Unidirectional Data Flow
field(name: null),
field(phone: null)
name: Joe,
phone: null
field(name: null),
field(phone: null)
name: null,
phone: null
Unidirectional Data Flow
field(name: null),
field(phone: null)
name: Joe,
phone: null
name: null,
phone: null
field(name: Joe),
field(phone: null)
Unidirectional Data Flow
field(name: null),
field(phone: null)
name: Joe,
phone: null
name: null,
phone: null
field(name: Joe),
field(phone: null)
field(name: Joe),
field(phone: null)
Unidirectional Data Flow
field(name: “Joe”),
field(phone: null)
name: Joe,
phone: null
name: null,
phone: null
field(name: Joe),
field(phone: null)
Unidirectional Data Flow
field(name: “Joe”),
field(phone: null)
name: Joe,
phone: null
name: null,
phone: 555
field(name: Joe),
field(phone: null)
Unidirectional Data Flow
field(name: “Joe”),
field(phone: null)
name: Joe,
phone: 555
name: null,
phone: 555
field(name: Joe),
field(phone: null)
Unidirectional Data Flow
field(name: “Joe”),
field(phone: null)
name: Joe,
phone: 555
name: null,
phone: 555
field(name: Joe),
field(phone: 555)
Unidirectional Data Flow
field(name: “Joe”),
field(phone: null)
name: Joe,
phone: 555
name: null,
phone: 555
field(name: Joe),
field(phone: 555)
field(name: Joe),
field(phone: 555)
Unidirectional Data Flow
field(name: “Joe”),
field(phone: “555”)
name: Joe,
phone: 555
name: null,
phone: 555
field(name: Joe),
field(phone: 555)
Is that it?
Is that it?
● Database changes
● Handling conflicts
● Different field types
● Sections, ordering
● Filtering
● Navigation
● Prefilled values
● Validations
● Persisting
● Confirmations, discarding changes
● ...
Configuration
Provider Reducer
Fields Builder
View
Store - key concepts
● Directed acyclic graph
● Single Store and Reducer implementations
● Unit tested the most
● Composition of simple dependencies unique per business type
● Dagger as a glue
Implementation
Implementation
class Store<FieldIdentifier>(
private val reducer: Reducer<FieldIdentifier>,
private val layoutProcessor: LayoutProcessor<FieldIdentifier>,
private val fieldsBuilder: FieldsBuilder<FieldIdentifier>,
//…
) {
fun start(initialState: State<FieldIdentifier>) {
//…
}
fun stop() {
//...
}
}
Implementation
class Store<FieldIdentifier>(
private val reducer: Reducer<FieldIdentifier>,
private val layoutProcessor: LayoutProcessor<FieldIdentifier>,
private val fieldsBuilder: FieldsBuilder<FieldIdentifier>,
//…
) {
fun start(initialState: State<FieldIdentifier>) {
//…
}
fun stop() {
//...
}
}
Implementation
class Store<FieldIdentifier>(
private val reducer: Reducer<FieldIdentifier>,
private val layoutProcessor: LayoutProcessor<FieldIdentifier>,
private val fieldsBuilder: FieldsBuilder<FieldIdentifier>,
//…
) {
fun start(initialState: State<FieldIdentifier>) {
//…
}
fun stop() {
//...
}
}
Implementation
class Reducer<FieldIdentifier> {
fun reduce(
fields: Observable<Set<FieldIdentifier>>,
userUpdates: Observable<Set<FieldIdentifier>>,
//...
): Observable<State<FieldIdentifier>>
}
Implementation
class Reducer<FieldIdentifier> {
fun reduce(
fields: Observable<Set<FieldIdentifier>>,
userUpdates: Observable<Set<FieldIdentifier>>,
//...
): Observable<State<FieldIdentifier>> {
return Observable
.merge(fields, userUpdated /* ... */)
.scan(initialState) { state, event ->
// Build new state
}
}
}
Implementation
sealed class ContactFieldIdentifier {
object Name : ContactFieldIdentifier()
object Phone : ContactFieldIdentifier()
sealed class ContactSectionIdentifier : ContactFieldIdentifier() {
object DefaultSection : ContactSectionIdentifier()
object ContactInformationSection : ContactSectionIdentifier()
}
}
Implementation
class ContactConfigurationProvider : ConfigurationProvider<ContactFieldIdentifier> {
fun getFields(): Observable<Set<ContactFieldIdentifier>>
//...
}
}
class ContactFieldValuesProvider : FieldValuesProvider<ContactFieldIdentifier> {
fun getFieldValues(fields: Set<ContactFieldIdentifier>):
Observable<Map<ContactFieldIdentifier, Value?>> {
//...
}
}
sealed class Value {
data class LongValue(val value: Long) : Value()
data class StringValue(val value: String) : Value()
//...
}
The graph
The graph - challenges
● Responsibilities
● Invalidations
● Side effects
● Unexpected requirements
The graph - challenges
● Clear flow
● Threading
● Debugging
● Extensibility
Cycles
View
Reducer
Configuration
Provider
Store
Fields Builder
View
Reducer
Configuration
Provider
Store
Display Values
Provider
Fields Builder
View
name: Joe,
company: 1
Store
View
name: Joe,
company: 1
name: Joe,
company: 1
Store
View
name: Joe,
company: 1
name: Joe,
company: 1
Store
name: Joe,
company: VW
View
name: Joe,
company: 1
name: Joe,
company: 1
Store
name: Joe,
company: VW
field(name: Joe),
field(company: {1, VW})
View
name: Joe,
company: 1
name: Joe,
company: 1
Store
name: Joe,
company: VW
field(name: Joe),
field(company: {1, VW})
View
name: Joe,
company: 1
name: Joe,
company: 1
Store
name: Joe,
company: VW
field(name: Joe),
field(company: 1)
Fallback:
company: null
View
name: Joe,
company: null
name: Joe,
company: 1
Store
name: Joe,
company: VW
field(name: Joe),
field(company: 1)
Fallback:
company: null
View
name: Joe,
company: null
name: Joe,
company: 1
Store
name: Joe,
company: null
field(name: Joe),
field(company: null)
Fallback:
company: null
View
name: Joe,
company: null
name: Joe,
company: 1
Store
name: Joe,
company: null
field(name: Joe),
field(company: null)
Fallback:
company: null
Cycles
● Limit or remove
● Rethink early
● Watch out for Rx Subjects
View effects
View effects
● Scroll to a field, show Snackbar, close the screen
StoreView
State
Actions
View effects
● Scroll to a field, show Snackbar, close the screen
● Option 1: Pass them in State
StoreView
State
Actions
field(name: Joe),
effect(scroll to top)
View effects
● Scroll to a field, show Snackbar, close the screen
● Option 1: Pass them in State
StoreView
State
Actions
field(name: Joe),
effect(null)
View effects
● Scroll to a field, show Snackbar, close the screen
● Option 1: Pass them in State
● Option 2: Separate them
StoreView
State
Actions
effect(scroll to top)
A few more things
● Data modeling
● Separation from Android
● Mapping data to views
● Development process
● Future improvements
A few more things
● Data modeling
● Separation from Android
● Mapping data to views
● Development process
● Future improvements
Data modeling
● Kotlin is a major improvement over Java
Data classes, sealed classes, extension functions, lambdas
Data modeling
● Kotlin is a major improvement over Java
Data classes, sealed classes, extension functions, lambdas
● Android Runtime improvements
“Creating garbage is OK. Use the types and objects you need.”
Nicolas Geoffray, Android Runtime Team
A few more things
● Data modeling
● Separation from Android
● Mapping data to views
● Development process
● Future improvements
Separation from Android
● Build wrapper classes with interfaces and clear API
● Abstraction increase
● Designing an API will be on you!
fun requestPermissions(
usage: RuntimePermissionsUsage
): Observable<RuntimePermissionsResult>
A few more things
● Data modeling
● Separation from Android
● Mapping data to views
● Development process
● Future improvements
Mapping data to views
Mapping data to views
Epoxy
● Abstraction over RecyclerView
● Kotlin support, many add ons
EpoxyTouchHelper
.initSwiping(recyclerView)
.leftAndRight()
.withTarget(MySwippableModel::class.java)
.andCallbacks(swipeCallback)
A few more things
● Data modeling
● Separation from Android
● Mapping data to views
● Development process
● Future improvements
Development process
● Significant entry level
● Proficiency in reactive programming
Development process
● Significant entry level
● Proficiency in reactive programming
● Duplication and copy-pasting
“Prefer duplication over the wrong abstraction”
Sandi Metz
A few more things
● Data modeling
● Separation from Android
● Mapping data to views
● Development process
● Future improvements
Future improvements
● Splitting the Store (~200 LOC)
● Reevaluating existing cyclic dependencies
● More type-safe modelling
● Developer experience
○ Initial setup
○ Unified naming
○ Tracking or rewinding state
Conclusion
Conclusion
Old New
Inheritance Composition
Callbacks RxJava-based blocks
Mutable state Unidirectional flow
Modeling with primitives Higher level abstractions with Kotlin
No separation from Android SDK Android SDK kept in isolated blocks
Lack of tests
Unit tests for the core logic, Espresso
for integrations
Questions?
Thanks!
Don’t Forget!
Fill out the Session
Survey in the App
End Zoom Recording
Leave the room better
than you found it!
#ZES19
#ZES19

More Related Content

Similar to Building complex UI on Android

Agile Database Development with JSON
Agile Database Development with JSONAgile Database Development with JSON
Agile Database Development with JSONChris Saxon
 
Evolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB StitchEvolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB StitchMongoDB
 
Yesplan: 10 Years later
Yesplan: 10 Years laterYesplan: 10 Years later
Yesplan: 10 Years laterPharo
 
Fast REST APIs Development with MongoDB
Fast REST APIs Development with MongoDBFast REST APIs Development with MongoDB
Fast REST APIs Development with MongoDBMongoDB
 
Patterns of Enterprise Application Architecture (by example)
Patterns of Enterprise Application Architecture (by example)Patterns of Enterprise Application Architecture (by example)
Patterns of Enterprise Application Architecture (by example)Paulo Gandra de Sousa
 
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...Ted Chien
 
Android_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_EngineeringAndroid_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_EngineeringShivanshSeth6
 
React native: building shared components for Android and iOS
React native: building shared components for Android and iOSReact native: building shared components for Android and iOS
React native: building shared components for Android and iOSCalum Gathergood
 
Notes (2012-06-08)
Notes (2012-06-08)Notes (2012-06-08)
Notes (2012-06-08)Chris Pitt
 
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB StitchMongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB StitchMongoDB
 
Breaking the oracle tie
Breaking the oracle tieBreaking the oracle tie
Breaking the oracle tieagiamas
 
PredictionIO - Building Applications That Predict User Behavior Through Big D...
PredictionIO - Building Applications That Predict User Behavior Through Big D...PredictionIO - Building Applications That Predict User Behavior Through Big D...
PredictionIO - Building Applications That Predict User Behavior Through Big D...predictionio
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB
 
Pre-Aggregated Analytics And Social Feeds Using MongoDB
Pre-Aggregated Analytics And Social Feeds Using MongoDBPre-Aggregated Analytics And Social Feeds Using MongoDB
Pre-Aggregated Analytics And Social Feeds Using MongoDBRackspace
 
From Monkey Coders To Smart Gorillas - Web Summit 2014
From Monkey Coders To Smart Gorillas - Web Summit 2014From Monkey Coders To Smart Gorillas - Web Summit 2014
From Monkey Coders To Smart Gorillas - Web Summit 2014José Ignacio Fernández
 
Rockin' the Web into the Next Dimension: JQueryTO 2014 Final Keynote
Rockin' the Web into the Next Dimension: JQueryTO 2014 Final KeynoteRockin' the Web into the Next Dimension: JQueryTO 2014 Final Keynote
Rockin' the Web into the Next Dimension: JQueryTO 2014 Final KeynoteVerold
 
Google Developer Group(GDG) DevFest Event 2012 Android talk
Google Developer Group(GDG) DevFest Event 2012 Android talkGoogle Developer Group(GDG) DevFest Event 2012 Android talk
Google Developer Group(GDG) DevFest Event 2012 Android talkImam Raza
 

Similar to Building complex UI on Android (20)

Agile Database Development with JSON
Agile Database Development with JSONAgile Database Development with JSON
Agile Database Development with JSON
 
Evolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB StitchEvolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB Stitch
 
Yesplan: 10 Years later
Yesplan: 10 Years laterYesplan: 10 Years later
Yesplan: 10 Years later
 
Fast REST APIs Development with MongoDB
Fast REST APIs Development with MongoDBFast REST APIs Development with MongoDB
Fast REST APIs Development with MongoDB
 
PoEAA by Example
PoEAA by ExamplePoEAA by Example
PoEAA by Example
 
Patterns of Enterprise Application Architecture (by example)
Patterns of Enterprise Application Architecture (by example)Patterns of Enterprise Application Architecture (by example)
Patterns of Enterprise Application Architecture (by example)
 
Resume_Sharvani
Resume_SharvaniResume_Sharvani
Resume_Sharvani
 
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
 
Android_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_EngineeringAndroid_Bootcamp_PPT_GDSC_ITS_Engineering
Android_Bootcamp_PPT_GDSC_ITS_Engineering
 
React native: building shared components for Android and iOS
React native: building shared components for Android and iOSReact native: building shared components for Android and iOS
React native: building shared components for Android and iOS
 
Notes (2012-06-08)
Notes (2012-06-08)Notes (2012-06-08)
Notes (2012-06-08)
 
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB StitchMongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
MongoDB.local Sydney: Evolving your Data Access with MongoDB Stitch
 
Huge web apps web expo 2013
Huge web apps web expo 2013Huge web apps web expo 2013
Huge web apps web expo 2013
 
Breaking the oracle tie
Breaking the oracle tieBreaking the oracle tie
Breaking the oracle tie
 
PredictionIO - Building Applications That Predict User Behavior Through Big D...
PredictionIO - Building Applications That Predict User Behavior Through Big D...PredictionIO - Building Applications That Predict User Behavior Through Big D...
PredictionIO - Building Applications That Predict User Behavior Through Big D...
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDB
 
Pre-Aggregated Analytics And Social Feeds Using MongoDB
Pre-Aggregated Analytics And Social Feeds Using MongoDBPre-Aggregated Analytics And Social Feeds Using MongoDB
Pre-Aggregated Analytics And Social Feeds Using MongoDB
 
From Monkey Coders To Smart Gorillas - Web Summit 2014
From Monkey Coders To Smart Gorillas - Web Summit 2014From Monkey Coders To Smart Gorillas - Web Summit 2014
From Monkey Coders To Smart Gorillas - Web Summit 2014
 
Rockin' the Web into the Next Dimension: JQueryTO 2014 Final Keynote
Rockin' the Web into the Next Dimension: JQueryTO 2014 Final KeynoteRockin' the Web into the Next Dimension: JQueryTO 2014 Final Keynote
Rockin' the Web into the Next Dimension: JQueryTO 2014 Final Keynote
 
Google Developer Group(GDG) DevFest Event 2012 Android talk
Google Developer Group(GDG) DevFest Event 2012 Android talkGoogle Developer Group(GDG) DevFest Event 2012 Android talk
Google Developer Group(GDG) DevFest Event 2012 Android talk
 

Recently uploaded

EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Intelisync
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
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 CCTVshikhaohhpro
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
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.docxComplianceQuest1
 
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.pdfkalichargn70th171
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
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 ApplicationsAlberto González Trastoy
 
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.pdfkalichargn70th171
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 

Recently uploaded (20)

EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)Introduction to Decentralized Applications (dApps)
Introduction to Decentralized Applications (dApps)
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
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
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
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
 
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
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
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
 
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
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 

Building complex UI on Android