SlideShare a Scribd company logo
1 of 66
Download to read offline
ONLINE-OFFLINE
Developing Apps for Emerging Markets
OFF GRID ELECTRIC
From: https://medium.com/@Offgrid
OFF GRID ELECTRIC
AGENDA
ARCHITECTURE
LIBRARIES
CHALLENGES
ARCHITECTURE
BE USEFUL
My App
‣Store data locally
‣Separate UI and network
‣Queue requests
MVP(Model View Presenter)
EVENT BUS
DATABASE
REPOSITORY
REPOSITORY
ACTIVITY
FRAGMENT
JOBS
PRESENTER
PRESENTER
SERVICE
DISPLAY A VIEW
PRESENTER
SERVICE
ACTIVITY
EVENT BUS
DATABASE
REPOSITORY
TAKE AN ACTION
PRESENTER
SERVICE
ACTIVITY
EVENT BUS
DATABASEREPOSITORY
JOB NETWORK
APP SERVER
AGREE ON
‣Conflict Resolution
‣Adding Timestamps to Requests
‣Bundling Requests
‣Use of Status Fields
EVENT BUS
DATABASE
REPOSITORY
REPOSITORY
ACTIVITY
FRAGMENT
JOBS
PRESENTER
PRESENTER
SERVICE
LIBRARIES
WHAT WE USE
‣Realm
‣EventBus
‣Android Job
STORE DATA LOCALLY
REALM
▸Easy to Set Up
▸Faster than ORMs
▸Has a Fluent API
REALM - MODEL CLASS
@RealmClass

public class Place implements RealmModel

{

}
REALM - MODEL CLASS
@RealmClass

public class Place implements RealmModel

{

@PrimaryKey

private String localId;
@Index

private Long remoteId;

private Gps location;

…
}
REALM - MODEL CLASS
localId remoteId location
19444498-2a40… 1458260
65031f36-bde9…
e85c9757-f546…
REALM - ADDING A RECORD
public class PlaceRepository implements Repository<Place>

{

@Override

public void add (final Place item)

{



}
…
REALM - ADDING A RECORD
public class PlaceRepository implements Repository<Place>

{

@Override

public void add (final Place item)

{

Realm realm = Realm.getDefaultInstance();

realm.executeTransaction( (realm) -> {

realm.copyToRealmOrUpdate( item );

} );

realm.close();

}
…
REALM - QUERY RESULT
private static final String PLACE_ID = "id";
@Override

public Place toResult (Realm realm)

{

return realm.where( Place.class )



}
REALM - QUERY RESULT
private static final String PLACE_ID = "id";
@Override

public Place toResult (Realm realm)

{

return realm.where( Place.class )

.equalTo( PLACE_ID, placeId )

.findFirst();

}
SEPARATE UI AND
NETWORK
EVENTBUS
From: http://greenrobot.org/eventbus
… WHEN YOU HAVE LOTS OF OBJECTS THAT
ARE POTENTIAL EVENT SOURCES.
Martin Fowler
EVENTBUS
EVENTBUS - SETUP
@Provides

@Singleton

public Bus provideBus ()

{

return new Bus( EventBus.builder()

.logNoSubscriberMessages( BuildConfig.DEBUG )

.throwSubscriberException( false )

.build() );

}
EVENTBUS - REGISTER
public class LeadsMapPresenter

{

private final Bus bus;

private LeadsMapView leadsMapView;



@Inject

LeadsMapPresenter (Bus bus)

{

this.bus = bus;

}



…
EVENTBUS - REGISTER
public class LeadsMapPresenter

{

public void attachView (LeadsMapView view)

{

this.leadsMapView = view;

bus.register( this );

}
EVENTBUS - REGISTER
public class LeadsMapPresenter

{

public void attachView (LeadsMapView view)

{

this.leadsMapView = view;

bus.register( this );

}
public void detachView ()

{

this.leadsMapView = null;

bus.unregister( this );

}
TAKE AN ACTION
PRESENTER
SERVICE
ACTIVITY
EVENT BUS
DATABASEREPOSITORY
JOB NETWORK
EVENTBUS - POST EVENT
api.submitPlace( place ).enqueue( new Callback<Place>()

{

…
JOB
EVENTBUS - POST EVENT
api.submitPlace( place ).enqueue( new Callback<Place>()

{

@Override

public void onResponse (Call<Place> call, Response<Place> response)

{

if ( response.isSuccessful() )

{



}
…
JOB
EVENTBUS - POST EVENT
api.submitPlace( place ).enqueue( new Callback<Place>()

{

@Override

public void onResponse (Call<Place> call, Response<Place> response)

{

if ( response.isSuccessful() )

{

Place updatedPlace = response.body();

bus.post( new PlaceSubmissionSuccessEvent( updatedPlace ) );

}
…
JOB
EVENTBUS - RETRIEVE EVENT
public class LeadsMapPresenter

{


@Subscribe

public void onPlaceSubmissionSuccess (PlaceSubmissionSuccessEvent event)

{

leadsMapView.displaySuccessMessage( PLACE_SUCCESS );
}
…
PRESENTER
QUEUE REQUESTS
ANDROID JOB
ANDROID JOB
‣Alarm Manager
‣Job Scheduler
‣GCM Network Manager
ANDROID JOB
JOB MANAGER
JOB CREATOR
ANDROID JOB
JOB MANAGER
PROVIDER
JOB
JOB CREATOR
PROVIDER
JOB
PROVIDER
JOB
ANDROID JOB
JOB MANAGER
PROVIDER
JOB
JOB CREATOR
PROVIDER
JOB
PROVIDER
JOB
JOB REQUEST
ANDROID JOB
JOB MANAGER
PROVIDER
JOB
JOB CREATOR
PROVIDER
JOB
PROVIDER
JOB
JOB REQUEST
JOB
ANDROID JOB - CREATOR
@Singleton

public class ConfettiJobCreator implements JobCreator

{

@Inject

Map<String, Provider<Job>> jobs;



@Override

public Job create (String tag)

{



}

}
ANDROID JOB - CREATOR
@Singleton

public class ConfettiJobCreator implements JobCreator

{

@Inject

Map<String, Provider<Job>> jobs;



@Override

public Job create (String tag)

{

Provider<Job> jobProvider = jobs.get( tag );

return jobProvider.get();

}

}
ANDROID JOB - JOB EXECUTION
@Override

protected Result onRunJob (final Params params)

{



} JOB
ANDROID JOB - JOB EXECUTION
@Override

protected Result onRunJob (final Params params)

{

PersistableBundleCompat extras = params.getExtras();

String placeId = extras.getString( PARAM_PLACE_ID );





} JOB
ANDROID JOB - JOB EXECUTION
@Override

protected Result onRunJob (final Params params)

{

PersistableBundleCompat extras = params.getExtras();

String placeId = extras.getString( PARAM_PLACE_ID );



if ( submitRequest( placeId ) )

{

return Result.SUCCESS;

}

return Result.FAILURE;

} JOB
ANDROID JOB
JOB MANAGER
PROVIDER
JOB
JOB CREATOR
JOB REQUEST
JOB
ANDROID JOB - SCHEDULING
public static JobRequest buildJobRequest (String placeId)

{

PersistableBundleCompat extras = new PersistableBundleCompat();

extras.putString( PARAM_PLACE_ID, placeId );





}
ANDROID JOB - SCHEDULING
public static JobRequest buildJobRequest (String placeId)

{

PersistableBundleCompat extras = new PersistableBundleCompat();

extras.putString( PARAM_PLACE_ID, placeId );



return new JobRequest.Builder( SendPlaceRequestJob.JOB_TAG )



}
ANDROID JOB - SCHEDULING
public static JobRequest buildJobRequest (String placeId)

{

PersistableBundleCompat extras = new PersistableBundleCompat();

extras.putString( PARAM_PLACE_ID, placeId );



return new JobRequest.Builder( SendPlaceRequestJob.JOB_TAG )

.setExecutionWindow( 10_000L, 20_000L )

.setRequiredNetworkType( JobRequest.NetworkType.CONNECTED )



}
ANDROID JOB - SCHEDULING
public static JobRequest buildJobRequest (String placeId)

{

PersistableBundleCompat extras = new PersistableBundleCompat();

extras.putString( PARAM_PLACE_ID, placeId );



return new JobRequest.Builder( SendPlaceRequestJob.JOB_TAG )

.setExecutionWindow( 10_000L, 20_000L )

.setRequiredNetworkType( JobRequest.NetworkType.CONNECTED )

.setExtras( extras )



}
ANDROID JOB - SCHEDULING
public static JobRequest buildJobRequest (String placeId)

{

PersistableBundleCompat extras = new PersistableBundleCompat();

extras.putString( PARAM_PLACE_ID, placeId );



return new JobRequest.Builder( SendPlaceRequestJob.JOB_TAG )

.setExecutionWindow( 10_000L, 20_000L )

.setRequiredNetworkType( JobRequest.NetworkType.CONNECTED )

.setExtras( extras )

.setRequirementsEnforced( true )

.build();

}
ANDROID JOB - SCHEDULING
jobManager.schedule( );
ANDROID JOB - SCHEDULING
jobManager.schedule( SendPlaceRequestJob.buildJobRequest( id ) );
JOB REQUEST
JOB QUEUE
WHAT WE USE
‣Realm
‣EventBus
‣Android Job
CHALLENGES
WHAT’S NEXT?
‣RxJava
‣Mapbox
‣Push Notifications
THANKS
@brwngrldev
+AnnyceDavis
www.adavis.info

More Related Content

Similar to Developing Apps for Emerging Markets

GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...Bruno Salvatore Belluccia
 
Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017
Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017
Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017Codemotion
 
Creating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdfCreating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdfShaiAlmog1
 
Java 8 Hipster slides
Java 8 Hipster slidesJava 8 Hipster slides
Java 8 Hipster slidesOleg Prophet
 
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Astrails
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]Nilhcem
 
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngineGoogle Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngineRoman Kirillov
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developersPavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationAlexander Obukhov
 
Creating an Uber Clone - Part XVII.pdf
Creating an Uber Clone - Part XVII.pdfCreating an Uber Clone - Part XVII.pdf
Creating an Uber Clone - Part XVII.pdfShaiAlmog1
 
Deep Dive into React Hooks
Deep Dive into React HooksDeep Dive into React Hooks
Deep Dive into React HooksFelix Kühl
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidDaniel Baccin
 
Realm - Phoenix Mobile Festival
Realm - Phoenix Mobile FestivalRealm - Phoenix Mobile Festival
Realm - Phoenix Mobile FestivalDJ Rausch
 
Creating an Uber Clone - Part XXIX.pdf
Creating an Uber Clone - Part XXIX.pdfCreating an Uber Clone - Part XXIX.pdf
Creating an Uber Clone - Part XXIX.pdfShaiAlmog1
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionChristian Panadero
 
Quick and Easy Development with Node.js and Couchbase Server
Quick and Easy Development with Node.js and Couchbase ServerQuick and Easy Development with Node.js and Couchbase Server
Quick and Easy Development with Node.js and Couchbase ServerNic Raboy
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platformsAyush Sharma
 

Similar to Developing Apps for Emerging Markets (20)

GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
 
Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017
Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017
Going fullstack React(ive) - Paulo Lopes - Codemotion Amsterdam 2017
 
Creating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdfCreating an Uber Clone - Part XVII - Transcript.pdf
Creating an Uber Clone - Part XVII - Transcript.pdf
 
Java 8 Hipster slides
Java 8 Hipster slidesJava 8 Hipster slides
Java 8 Hipster slides
 
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.
 
The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]The 2016 Android Developer Toolbox [MOBILIZATION]
The 2016 Android Developer Toolbox [MOBILIZATION]
 
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngineGoogle Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generation
 
Creating an Uber Clone - Part XVII.pdf
Creating an Uber Clone - Part XVII.pdfCreating an Uber Clone - Part XVII.pdf
Creating an Uber Clone - Part XVII.pdf
 
Deep Dive into React Hooks
Deep Dive into React HooksDeep Dive into React Hooks
Deep Dive into React Hooks
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++
 
Realm - Phoenix Mobile Festival
Realm - Phoenix Mobile FestivalRealm - Phoenix Mobile Festival
Realm - Phoenix Mobile Festival
 
Creating an Uber Clone - Part XXIX.pdf
Creating an Uber Clone - Part XXIX.pdfCreating an Uber Clone - Part XXIX.pdf
Creating an Uber Clone - Part XXIX.pdf
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
 
Quick and Easy Development with Node.js and Couchbase Server
Quick and Easy Development with Node.js and Couchbase ServerQuick and Easy Development with Node.js and Couchbase Server
Quick and Easy Development with Node.js and Couchbase Server
 
Flask and Angular: An approach to build robust platforms
Flask and Angular:  An approach to build robust platformsFlask and Angular:  An approach to build robust platforms
Flask and Angular: An approach to build robust platforms
 

More from Annyce Davis

Getting a Grip on GraphQL
Getting a Grip on GraphQLGetting a Grip on GraphQL
Getting a Grip on GraphQLAnnyce Davis
 
First Do No Harm - 360|AnDev
First Do No Harm - 360|AnDevFirst Do No Harm - 360|AnDev
First Do No Harm - 360|AnDevAnnyce Davis
 
Creating Gradle Plugins - Oredev
Creating Gradle Plugins - OredevCreating Gradle Plugins - Oredev
Creating Gradle Plugins - OredevAnnyce Davis
 
Develop Maintainable Apps - edUiConf
Develop Maintainable Apps - edUiConfDevelop Maintainable Apps - edUiConf
Develop Maintainable Apps - edUiConfAnnyce Davis
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USAnnyce Davis
 
From Grails to Android: A Simple Journey
From Grails to Android: A Simple JourneyFrom Grails to Android: A Simple Journey
From Grails to Android: A Simple JourneyAnnyce Davis
 
Google I/O 2016 Recap
Google I/O 2016 RecapGoogle I/O 2016 Recap
Google I/O 2016 RecapAnnyce Davis
 
Screen Robots: UI Tests in Espresso
Screen Robots: UI Tests in EspressoScreen Robots: UI Tests in Espresso
Screen Robots: UI Tests in EspressoAnnyce Davis
 
Creating Gradle Plugins
Creating Gradle PluginsCreating Gradle Plugins
Creating Gradle PluginsAnnyce Davis
 
Static Code Analysis
Static Code AnalysisStatic Code Analysis
Static Code AnalysisAnnyce Davis
 
Develop Maintainable Apps
Develop Maintainable AppsDevelop Maintainable Apps
Develop Maintainable AppsAnnyce Davis
 
Android Testing, Why So Hard?!
Android Testing, Why So Hard?!Android Testing, Why So Hard?!
Android Testing, Why So Hard?!Annyce Davis
 
Measuring Audience Engagement through Analytics
Measuring Audience Engagement through AnalyticsMeasuring Audience Engagement through Analytics
Measuring Audience Engagement through AnalyticsAnnyce Davis
 
DC Media Innovations Kick-Off Meetup
DC Media Innovations Kick-Off MeetupDC Media Innovations Kick-Off Meetup
DC Media Innovations Kick-Off MeetupAnnyce Davis
 

More from Annyce Davis (15)

Getting a Grip on GraphQL
Getting a Grip on GraphQLGetting a Grip on GraphQL
Getting a Grip on GraphQL
 
First Do No Harm - 360|AnDev
First Do No Harm - 360|AnDevFirst Do No Harm - 360|AnDev
First Do No Harm - 360|AnDev
 
Creating Gradle Plugins - Oredev
Creating Gradle Plugins - OredevCreating Gradle Plugins - Oredev
Creating Gradle Plugins - Oredev
 
Develop Maintainable Apps - edUiConf
Develop Maintainable Apps - edUiConfDevelop Maintainable Apps - edUiConf
Develop Maintainable Apps - edUiConf
 
Creating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf USCreating Gradle Plugins - GR8Conf US
Creating Gradle Plugins - GR8Conf US
 
From Grails to Android: A Simple Journey
From Grails to Android: A Simple JourneyFrom Grails to Android: A Simple Journey
From Grails to Android: A Simple Journey
 
Google I/O 2016 Recap
Google I/O 2016 RecapGoogle I/O 2016 Recap
Google I/O 2016 Recap
 
Say It With Video
Say It With VideoSay It With Video
Say It With Video
 
Screen Robots: UI Tests in Espresso
Screen Robots: UI Tests in EspressoScreen Robots: UI Tests in Espresso
Screen Robots: UI Tests in Espresso
 
Creating Gradle Plugins
Creating Gradle PluginsCreating Gradle Plugins
Creating Gradle Plugins
 
Static Code Analysis
Static Code AnalysisStatic Code Analysis
Static Code Analysis
 
Develop Maintainable Apps
Develop Maintainable AppsDevelop Maintainable Apps
Develop Maintainable Apps
 
Android Testing, Why So Hard?!
Android Testing, Why So Hard?!Android Testing, Why So Hard?!
Android Testing, Why So Hard?!
 
Measuring Audience Engagement through Analytics
Measuring Audience Engagement through AnalyticsMeasuring Audience Engagement through Analytics
Measuring Audience Engagement through Analytics
 
DC Media Innovations Kick-Off Meetup
DC Media Innovations Kick-Off MeetupDC Media Innovations Kick-Off Meetup
DC Media Innovations Kick-Off Meetup
 

Recently uploaded

Leading Mobile App Development Companies in India (2).pdf
Leading Mobile App Development Companies in India (2).pdfLeading Mobile App Development Companies in India (2).pdf
Leading Mobile App Development Companies in India (2).pdfCWS Technology
 
Android Application Components with Implementation & Examples
Android Application Components with Implementation & ExamplesAndroid Application Components with Implementation & Examples
Android Application Components with Implementation & ExamplesChandrakantDivate1
 
Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...
Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...
Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...nishasame66
 
Mobile Application Development-Components and Layouts
Mobile Application Development-Components and LayoutsMobile Application Development-Components and Layouts
Mobile Application Development-Components and LayoutsChandrakantDivate1
 
Mobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s ToolsMobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s ToolsChandrakantDivate1
 

Recently uploaded (6)

Leading Mobile App Development Companies in India (2).pdf
Leading Mobile App Development Companies in India (2).pdfLeading Mobile App Development Companies in India (2).pdf
Leading Mobile App Development Companies in India (2).pdf
 
Android Application Components with Implementation & Examples
Android Application Components with Implementation & ExamplesAndroid Application Components with Implementation & Examples
Android Application Components with Implementation & Examples
 
Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...
Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...
Satara Call girl escort *74796//13122* Call me punam call girls 24*7hour avai...
 
Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)
Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)
Obat Penggugur Kandungan Di Apotik Kimia Farma (087776558899)
 
Mobile Application Development-Components and Layouts
Mobile Application Development-Components and LayoutsMobile Application Development-Components and Layouts
Mobile Application Development-Components and Layouts
 
Mobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s ToolsMobile Application Development-Android and It’s Tools
Mobile Application Development-Android and It’s Tools
 

Developing Apps for Emerging Markets