SlideShare a Scribd company logo
Creating an Uber Clone - Part XV
Next we’ll bind the websocket logic and map UI to bring this all together…
public class LocationService {
private static final short MESSAGE_TYPE_LOCATION_UPDATE = 1;
private static final short MESSAGE_TYPE_DRIVER_POSITIONS = 2;
private static final short MESSAGE_TYPE_AVAILBLE_DRIVER_POSITIONS = 3;
private static final long MAX_UPDATE_FREQUENCY = 3000;
private Location lastKnownLocation;
private SocketConnection server;
private CarAdded carCallback;
private SuccessCallback<Location> locationCallback;
private Map<Long, User> cars = new HashMap<>();
private LocationService() {}
public static void bind(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
new LocationService().bindImpl(carCallback, locationUpdate);
}
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
LocationService (Client)
We can get started with a LocationService class similarly to the UserService class that would abstract the local location. Unlike the UserService class the LocationService
class should also deal with the physical location of the device.

These are the same constants we have in the server
public class LocationService {
private static final short MESSAGE_TYPE_LOCATION_UPDATE = 1;
private static final short MESSAGE_TYPE_DRIVER_POSITIONS = 2;
private static final short MESSAGE_TYPE_AVAILBLE_DRIVER_POSITIONS = 3;
private static final long MAX_UPDATE_FREQUENCY = 3000;
private Location lastKnownLocation;
private SocketConnection server;
private CarAdded carCallback;
private SuccessCallback<Location> locationCallback;
private Map<Long, User> cars = new HashMap<>();
private LocationService() {}
public static void bind(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
new LocationService().bindImpl(carCallback, locationUpdate);
}
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
LocationService (Client)
When sending a location update to the server I don't want to exceed a fixed amount of updates so we won't burden the server or our network
public class LocationService {
private static final short MESSAGE_TYPE_LOCATION_UPDATE = 1;
private static final short MESSAGE_TYPE_DRIVER_POSITIONS = 2;
private static final short MESSAGE_TYPE_AVAILBLE_DRIVER_POSITIONS = 3;
private static final long MAX_UPDATE_FREQUENCY = 3000;
private Location lastKnownLocation;
private SocketConnection server;
private CarAdded carCallback;
private SuccessCallback<Location> locationCallback;
private Map<Long, User> cars = new HashMap<>();
private LocationService() {}
public static void bind(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
new LocationService().bindImpl(carCallback, locationUpdate);
}
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
LocationService (Client)
The class has a private constructor so the only way to create the LocationService is via the bind method which in turn invokes the instance method bindImpl. We provide
two callbacks one is for a car being added which we will use to bind a new car to the UI and the other is for location updates so we can position the map
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
public void locationUpdated(Location location) {
lastKnownLocation = location;
if(location.getStatus() == LocationManager.AVAILABLE &&
locationCallback != null) {
SuccessCallback<Location> c = locationCallback;
locationCallback = null;
c.onSucess(location);
}
if(server != null) {
server.sendLocationUpdate();
}
}
@Override
public void providerStateChanged(int newState) {
}
});
new SocketConnection().connect();
LocationService (Client)
Location update notifies the server about changes to the location and also invokes the callback once so we can position the map
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
public void locationUpdated(Location location) {
lastKnownLocation = location;
if(location.getStatus() == LocationManager.AVAILABLE &&
locationCallback != null) {
SuccessCallback<Location> c = locationCallback;
locationCallback = null;
c.onSucess(location);
}
if(server != null) {
server.sendLocationUpdate();
}
}
@Override
public void providerStateChanged(int newState) {
}
});
new SocketConnection().connect();
LocationService (Client)
We invoke the callback with the location so the map can be shifted to our current position
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
public void locationUpdated(Location location) {
lastKnownLocation = location;
if(location.getStatus() == LocationManager.AVAILABLE &&
locationCallback != null) {
SuccessCallback<Location> c = locationCallback;
locationCallback = null;
c.onSucess(location);
}
if(server != null) {
server.sendLocationUpdate();
}
}
@Override
public void providerStateChanged(int newState) {
}
});
new SocketConnection().connect();
LocationService (Client)
Once the server socket is connected we start sending location updates there
private void bindImpl(CarAdded carCallback,
SuccessCallback<Location> locationUpdate) {
this.carCallback = carCallback;
locationCallback = locationUpdate;
LocationManager.getLocationManager().
setLocationListener(new LocationListener() {
@Override
public void locationUpdated(Location location) {
lastKnownLocation = location;
if(location.getStatus() == LocationManager.AVAILABLE &&
locationCallback != null) {
SuccessCallback<Location> c = locationCallback;
locationCallback = null;
c.onSucess(location);
}
if(server != null) {
server.sendLocationUpdate();
}
}
@Override
public void providerStateChanged(int newState) {
}
});
new SocketConnection().connect();
LocationService (Client)
We open the WebSocket connection using the connect() call
new SocketConnection().connect();
}
class SocketConnection extends WebSocket {
private double lat, lon;
private float direction;
private long lastUpdateTime;
private EasyThread et;
public SocketConnection() {
super(Globals.SERVER_SOCKET_URL);
et = EasyThread.start("Websocket");
}
@Override
protected void onOpen() {
server = this;
sendLocationUpdate();
}
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
LocationService (Client)
We cache the last set of values so we don't send data to the server unless something changed
new SocketConnection().connect();
}
class SocketConnection extends WebSocket {
private double lat, lon;
private float direction;
private long lastUpdateTime;
private EasyThread et;
public SocketConnection() {
super(Globals.SERVER_SOCKET_URL);
et = EasyThread.start("Websocket");
}
@Override
protected void onOpen() {
server = this;
sendLocationUpdate();
}
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
LocationService (Client)
EasyThread lets us post "jobs" onto a dedicated thread so we don't have to block the main EDT. It also means we don't need to deal with synchronization or any other
complexity related to that as all operations happen on that thread
new SocketConnection().connect();
}
class SocketConnection extends WebSocket {
private double lat, lon;
private float direction;
private long lastUpdateTime;
private EasyThread et;
public SocketConnection() {
super(Globals.SERVER_SOCKET_URL);
et = EasyThread.start("Websocket");
}
@Override
protected void onOpen() {
server = this;
sendLocationUpdate();
}
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
LocationService (Client)
Until onOpen() is invoked the connection isn't ready. That's why the server member field is only initialized here when it's actually ready
new SocketConnection().connect();
}
class SocketConnection extends WebSocket {
private double lat, lon;
private float direction;
private long lastUpdateTime;
private EasyThread et;
public SocketConnection() {
super(Globals.SERVER_SOCKET_URL);
et = EasyThread.start("Websocket");
}
@Override
protected void onOpen() {
server = this;
sendLocationUpdate();
}
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
LocationService (Client)
If we already have a location we should send a user location update one we have the socket connection in place
new SocketConnection().connect();
}
class SocketConnection extends WebSocket {
private double lat, lon;
private float direction;
private long lastUpdateTime;
private EasyThread et;
public SocketConnection() {
super(Globals.SERVER_SOCKET_URL);
et = EasyThread.start("Websocket");
}
@Override
protected void onOpen() {
server = this;
sendLocationUpdate();
}
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
LocationService (Client)
The connection is single threaded as I mentioned before. The isThisIt() method is similar to isEDT() and indicates if the current thread is the one managed by the
EasyThread if not we use run(Runnable) which invokes the target Runnable on the EasyThread similarly to callSerially
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
float dir = lastKnownLocation.getDirection();
if(ll == lon && lt == lat && dir == direction) {
return;
}
long time = System.currentTimeMillis();
if(time - lastUpdateTime < MAX_UPDATE_FREQUENCY) {
return;
}
lastUpdateTime = time;
lon = ll;
lat = lt;
direction = dir;
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);) {
dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE);
String token = Preferences.get("token", null);
LocationService (Client)
If the values didn't change since last update so we do nothing
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
float dir = lastKnownLocation.getDirection();
if(ll == lon && lt == lat && dir == direction) {
return;
}
long time = System.currentTimeMillis();
if(time - lastUpdateTime < MAX_UPDATE_FREQUENCY) {
return;
}
lastUpdateTime = time;
lon = ll;
lat = lt;
direction = dir;
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);) {
dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE);
String token = Preferences.get("token", null);
LocationService (Client)
We don't update too much, there is a chance we'll miss an update here but it's probably not a deal breaker if a user didn't move much
public void sendLocationUpdate() {
if(!et.isThisIt()) {
et.run(() -> sendLocationUpdate());
return;
}
if(lastKnownLocation != null) {
double lt = lastKnownLocation.getLatitude();
double ll = lastKnownLocation.getLongitude();
float dir = lastKnownLocation.getDirection();
if(ll == lon && lt == lat && dir == direction) {
return;
}
long time = System.currentTimeMillis();
if(time - lastUpdateTime < MAX_UPDATE_FREQUENCY) {
return;
}
lastUpdateTime = time;
lon = ll;
lat = lt;
direction = dir;
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);) {
dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE);
String token = Preferences.get("token", null);
LocationService (Client)
We create a ByteArrayOutputStream into which we construct the message that we receive on the server with the header, location etc.
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);) {
dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE);
String token = Preferences.get("token", null);
dos.writeShort(token.length());
for(int iter = 0 ; iter < token.length() ; iter++) {
dos.writeByte((byte)token.charAt(iter));
}
dos.writeDouble(lat);
dos.writeDouble(lon);
dos.writeFloat(dir);
dos.writeDouble(1);
dos.writeByte(0);
dos.flush();
send(bos.toByteArray());
} catch(IOException err) {
Log.e(err);
}
}
}
@Override
protected void onClose(int i, String string) {
Log.p("Connection closed! Error... "
LocationService (Client)
I currently hardcoded a 1 kilometer search radius and defined explicitly that we aren't in taxi hailing mode
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);) {
dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE);
String token = Preferences.get("token", null);
dos.writeShort(token.length());
for(int iter = 0 ; iter < token.length() ; iter++) {
dos.writeByte((byte)token.charAt(iter));
}
dos.writeDouble(lat);
dos.writeDouble(lon);
dos.writeFloat(dir);
dos.writeDouble(1);
dos.writeByte(0);
dos.flush();
send(bos.toByteArray());
} catch(IOException err) {
Log.e(err);
}
}
}
@Override
protected void onClose(int i, String string) {
Log.p("Connection closed! Error... "
LocationService (Client)
One line to actually send the binary data, it would be similar with text data with the exception of parsing overhead. The IOException isn't likely as this is a RAM based
stream
try(ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);) {
dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE);
String token = Preferences.get("token", null);
dos.writeShort(token.length());
for(int iter = 0 ; iter < token.length() ; iter++) {
dos.writeByte((byte)token.charAt(iter));
}
dos.writeDouble(lat);
dos.writeDouble(lon);
dos.writeFloat(dir);
dos.writeDouble(1);
dos.writeByte(0);
dos.flush();
send(bos.toByteArray());
} catch(IOException err) {
Log.e(err);
}
}
}
@Override
protected void onClose(int i, String string) {
Log.p("Connection closed! Error... "
LocationService (Client)
The IOException isn't likely as this is a RAM based stream
@Override
protected void onClose(int i, String string) {
Log.p("Connection closed! Error... "
+ "trying to reconnect in 5 seconds");
UITimer.timer(5000, false, () -> connect());
}
@Override
protected void onMessage(String string) {
}
@Override
protected void onMessage(byte[] bytes) {
try {
DataInputStream dis = new DataInputStream(
new ByteArrayInputStream(bytes));
short response = dis.readShort();
int size = dis.readInt();
for(int iter = 0 ; iter < size ; iter++) {
long id = dis.readLong();
User car = cars.get(id);
if(car == null) {
car = new User().
id.set(id).
latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
LocationService (Client)
Here we receive the messages sent from the server specifically driver search results
@Override
protected void onClose(int i, String string) {
Log.p("Connection closed! Error... "
+ "trying to reconnect in 5 seconds");
UITimer.timer(5000, false, () -> connect());
}
@Override
protected void onMessage(String string) {
}
@Override
protected void onMessage(byte[] bytes) {
try {
DataInputStream dis = new DataInputStream(
new ByteArrayInputStream(bytes));
short response = dis.readShort();
int size = dis.readInt();
for(int iter = 0 ; iter < size ; iter++) {
long id = dis.readLong();
User car = cars.get(id);
if(car == null) {
car = new User().
id.set(id).
latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
LocationService (Client)
We store User instances in a Map where the user ID is the key. This saves us from sending duplicate carAdded events and allows us to just mutate the User properties
which other code can observe using the builtin listeners in properties
long id = dis.readLong();
User car = cars.get(id);
if(car == null) {
car = new User().
id.set(id).
latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
direction.set(dis.readFloat());
cars.put(id, car);
User finalCar = car;
callSerially(() -> carCallback.carAdded(finalCar));
} else {
car.latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
direction.set(dis.readFloat());
}
}
} catch(IOException err) {
Log.e(err);
}
}
protected void onError(Exception e) {
Log.e(e);
}
LocationService (Client)
Notice that this code is running on the WebSocket thread so events need to go back into the EDT to prevent potential issues
long id = dis.readLong();
User car = cars.get(id);
if(car == null) {
car = new User().
id.set(id).
latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
direction.set(dis.readFloat());
cars.put(id, car);
User finalCar = car;
callSerially(() -> carCallback.carAdded(finalCar));
} else {
car.latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
direction.set(dis.readFloat());
}
}
} catch(IOException err) {
Log.e(err);
}
}
protected void onError(Exception e) {
Log.e(e);
}
LocationService (Client)
This is really important, we need handle errors properly in a WebSocket application otherwise a failure can leave us without a connection
latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
direction.set(dis.readFloat());
cars.put(id, car);
User finalCar = car;
callSerially(() -> carCallback.carAdded(finalCar));
} else {
car.latitude.set(dis.readDouble()).
longitude.set(dis.readDouble()).
direction.set(dis.readFloat());
}
}
} catch(IOException err) {
Log.e(err);
}
}
protected void onError(Exception e) {
Log.e(e);
}
}
public static interface CarAdded {
void carAdded(User driver);
}
}
LocationService (Client)
The callback interface is trivial, it's mostly used as a lambda expression in the code… And that’s it for the location service…

More Related Content

Similar to Creating an Uber Clone - Part XV - Transcript.pdf

Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
Paweł Kowalczuk
 
Creating an Uber Clone - Part XXV - Transcript.pdf
Creating an Uber Clone - Part XXV - Transcript.pdfCreating an Uber Clone - Part XXV - Transcript.pdf
Creating an Uber Clone - Part XXV - Transcript.pdf
ShaiAlmog1
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
Yakov Fain
 
Creating an Uber Clone - Part XII.pdf
Creating an Uber Clone - Part XII.pdfCreating an Uber Clone - Part XII.pdf
Creating an Uber Clone - Part XII.pdf
ShaiAlmog1
 
Advanced Akka For Architects
Advanced Akka For ArchitectsAdvanced Akka For Architects
Advanced Akka For Architects
Lightbend
 
Lecture 10 Networking on Mobile Devices
Lecture 10 Networking on Mobile DevicesLecture 10 Networking on Mobile Devices
Lecture 10 Networking on Mobile Devices
Maksym Davydov
 
$q and Promises in AngularJS
$q and Promises in AngularJS $q and Promises in AngularJS
$q and Promises in AngularJS
a_sharif
 
Android Networking
Android NetworkingAndroid Networking
Android Networking
Maksym Davydov
 
Better react/redux apps using redux-saga
Better react/redux apps using redux-sagaBetter react/redux apps using redux-saga
Better react/redux apps using redux-saga
Younes (omar) Meliani
 
React lecture
React lectureReact lecture
React lecture
Christoffer Noring
 
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
ShaiAlmog1
 
How to use geolocation in react native apps
How to use geolocation in react native appsHow to use geolocation in react native apps
How to use geolocation in react native apps
InnovationM
 
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
Codemotion
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
ShaiAlmog1
 
ReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of IIReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of II
manuelmaly
 
DIY Uber
DIY UberDIY Uber
DIY Uber
NSCoder Mexico
 
Creating an Uber Clone - Part XXX - Transcript.pdf
Creating an Uber Clone - Part XXX - Transcript.pdfCreating an Uber Clone - Part XXX - Transcript.pdf
Creating an Uber Clone - Part XXX - Transcript.pdf
ShaiAlmog1
 
Average- An android project
Average- An android projectAverage- An android project
Average- An android projectIpsit Dash
 
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
DevClub_lv
 
Mobile webapplication development
Mobile webapplication developmentMobile webapplication development
Mobile webapplication development
Ganesh Gembali
 

Similar to Creating an Uber Clone - Part XV - Transcript.pdf (20)

Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Creating an Uber Clone - Part XXV - Transcript.pdf
Creating an Uber Clone - Part XXV - Transcript.pdfCreating an Uber Clone - Part XXV - Transcript.pdf
Creating an Uber Clone - Part XXV - Transcript.pdf
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
 
Creating an Uber Clone - Part XII.pdf
Creating an Uber Clone - Part XII.pdfCreating an Uber Clone - Part XII.pdf
Creating an Uber Clone - Part XII.pdf
 
Advanced Akka For Architects
Advanced Akka For ArchitectsAdvanced Akka For Architects
Advanced Akka For Architects
 
Lecture 10 Networking on Mobile Devices
Lecture 10 Networking on Mobile DevicesLecture 10 Networking on Mobile Devices
Lecture 10 Networking on Mobile Devices
 
$q and Promises in AngularJS
$q and Promises in AngularJS $q and Promises in AngularJS
$q and Promises in AngularJS
 
Android Networking
Android NetworkingAndroid Networking
Android Networking
 
Better react/redux apps using redux-saga
Better react/redux apps using redux-sagaBetter react/redux apps using redux-saga
Better react/redux apps using redux-saga
 
React lecture
React lectureReact lecture
React lecture
 
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
 
How to use geolocation in react native apps
How to use geolocation in react native appsHow to use geolocation in react native apps
How to use geolocation in react native apps
 
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 a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
ReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of IIReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of II
 
DIY Uber
DIY UberDIY Uber
DIY Uber
 
Creating an Uber Clone - Part XXX - Transcript.pdf
Creating an Uber Clone - Part XXX - Transcript.pdfCreating an Uber Clone - Part XXX - Transcript.pdf
Creating an Uber Clone - Part XXX - Transcript.pdf
 
Average- An android project
Average- An android projectAverage- An android project
Average- An android project
 
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019Managing State in React Apps with RxJS by James Wright at FrontCon 2019
Managing State in React Apps with RxJS by James Wright at FrontCon 2019
 
Mobile webapplication development
Mobile webapplication developmentMobile webapplication development
Mobile webapplication development
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfCreating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdf
ShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfCreating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdf
 

Recently uploaded

Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
Bhaskar Mitra
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 

Recently uploaded (20)

Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 

Creating an Uber Clone - Part XV - Transcript.pdf

  • 1. Creating an Uber Clone - Part XV Next we’ll bind the websocket logic and map UI to bring this all together…
  • 2. public class LocationService { private static final short MESSAGE_TYPE_LOCATION_UPDATE = 1; private static final short MESSAGE_TYPE_DRIVER_POSITIONS = 2; private static final short MESSAGE_TYPE_AVAILBLE_DRIVER_POSITIONS = 3; private static final long MAX_UPDATE_FREQUENCY = 3000; private Location lastKnownLocation; private SocketConnection server; private CarAdded carCallback; private SuccessCallback<Location> locationCallback; private Map<Long, User> cars = new HashMap<>(); private LocationService() {} public static void bind(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { new LocationService().bindImpl(carCallback, locationUpdate); } private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override LocationService (Client) We can get started with a LocationService class similarly to the UserService class that would abstract the local location. Unlike the UserService class the LocationService class should also deal with the physical location of the device. These are the same constants we have in the server
  • 3. public class LocationService { private static final short MESSAGE_TYPE_LOCATION_UPDATE = 1; private static final short MESSAGE_TYPE_DRIVER_POSITIONS = 2; private static final short MESSAGE_TYPE_AVAILBLE_DRIVER_POSITIONS = 3; private static final long MAX_UPDATE_FREQUENCY = 3000; private Location lastKnownLocation; private SocketConnection server; private CarAdded carCallback; private SuccessCallback<Location> locationCallback; private Map<Long, User> cars = new HashMap<>(); private LocationService() {} public static void bind(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { new LocationService().bindImpl(carCallback, locationUpdate); } private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override LocationService (Client) When sending a location update to the server I don't want to exceed a fixed amount of updates so we won't burden the server or our network
  • 4. public class LocationService { private static final short MESSAGE_TYPE_LOCATION_UPDATE = 1; private static final short MESSAGE_TYPE_DRIVER_POSITIONS = 2; private static final short MESSAGE_TYPE_AVAILBLE_DRIVER_POSITIONS = 3; private static final long MAX_UPDATE_FREQUENCY = 3000; private Location lastKnownLocation; private SocketConnection server; private CarAdded carCallback; private SuccessCallback<Location> locationCallback; private Map<Long, User> cars = new HashMap<>(); private LocationService() {} public static void bind(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { new LocationService().bindImpl(carCallback, locationUpdate); } private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override LocationService (Client) The class has a private constructor so the only way to create the LocationService is via the bind method which in turn invokes the instance method bindImpl. We provide two callbacks one is for a car being added which we will use to bind a new car to the UI and the other is for location updates so we can position the map
  • 5. private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override public void locationUpdated(Location location) { lastKnownLocation = location; if(location.getStatus() == LocationManager.AVAILABLE && locationCallback != null) { SuccessCallback<Location> c = locationCallback; locationCallback = null; c.onSucess(location); } if(server != null) { server.sendLocationUpdate(); } } @Override public void providerStateChanged(int newState) { } }); new SocketConnection().connect(); LocationService (Client) Location update notifies the server about changes to the location and also invokes the callback once so we can position the map
  • 6. private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override public void locationUpdated(Location location) { lastKnownLocation = location; if(location.getStatus() == LocationManager.AVAILABLE && locationCallback != null) { SuccessCallback<Location> c = locationCallback; locationCallback = null; c.onSucess(location); } if(server != null) { server.sendLocationUpdate(); } } @Override public void providerStateChanged(int newState) { } }); new SocketConnection().connect(); LocationService (Client) We invoke the callback with the location so the map can be shifted to our current position
  • 7. private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override public void locationUpdated(Location location) { lastKnownLocation = location; if(location.getStatus() == LocationManager.AVAILABLE && locationCallback != null) { SuccessCallback<Location> c = locationCallback; locationCallback = null; c.onSucess(location); } if(server != null) { server.sendLocationUpdate(); } } @Override public void providerStateChanged(int newState) { } }); new SocketConnection().connect(); LocationService (Client) Once the server socket is connected we start sending location updates there
  • 8. private void bindImpl(CarAdded carCallback, SuccessCallback<Location> locationUpdate) { this.carCallback = carCallback; locationCallback = locationUpdate; LocationManager.getLocationManager(). setLocationListener(new LocationListener() { @Override public void locationUpdated(Location location) { lastKnownLocation = location; if(location.getStatus() == LocationManager.AVAILABLE && locationCallback != null) { SuccessCallback<Location> c = locationCallback; locationCallback = null; c.onSucess(location); } if(server != null) { server.sendLocationUpdate(); } } @Override public void providerStateChanged(int newState) { } }); new SocketConnection().connect(); LocationService (Client) We open the WebSocket connection using the connect() call
  • 9. new SocketConnection().connect(); } class SocketConnection extends WebSocket { private double lat, lon; private float direction; private long lastUpdateTime; private EasyThread et; public SocketConnection() { super(Globals.SERVER_SOCKET_URL); et = EasyThread.start("Websocket"); } @Override protected void onOpen() { server = this; sendLocationUpdate(); } public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); LocationService (Client) We cache the last set of values so we don't send data to the server unless something changed
  • 10. new SocketConnection().connect(); } class SocketConnection extends WebSocket { private double lat, lon; private float direction; private long lastUpdateTime; private EasyThread et; public SocketConnection() { super(Globals.SERVER_SOCKET_URL); et = EasyThread.start("Websocket"); } @Override protected void onOpen() { server = this; sendLocationUpdate(); } public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); LocationService (Client) EasyThread lets us post "jobs" onto a dedicated thread so we don't have to block the main EDT. It also means we don't need to deal with synchronization or any other complexity related to that as all operations happen on that thread
  • 11. new SocketConnection().connect(); } class SocketConnection extends WebSocket { private double lat, lon; private float direction; private long lastUpdateTime; private EasyThread et; public SocketConnection() { super(Globals.SERVER_SOCKET_URL); et = EasyThread.start("Websocket"); } @Override protected void onOpen() { server = this; sendLocationUpdate(); } public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); LocationService (Client) Until onOpen() is invoked the connection isn't ready. That's why the server member field is only initialized here when it's actually ready
  • 12. new SocketConnection().connect(); } class SocketConnection extends WebSocket { private double lat, lon; private float direction; private long lastUpdateTime; private EasyThread et; public SocketConnection() { super(Globals.SERVER_SOCKET_URL); et = EasyThread.start("Websocket"); } @Override protected void onOpen() { server = this; sendLocationUpdate(); } public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); LocationService (Client) If we already have a location we should send a user location update one we have the socket connection in place
  • 13. new SocketConnection().connect(); } class SocketConnection extends WebSocket { private double lat, lon; private float direction; private long lastUpdateTime; private EasyThread et; public SocketConnection() { super(Globals.SERVER_SOCKET_URL); et = EasyThread.start("Websocket"); } @Override protected void onOpen() { server = this; sendLocationUpdate(); } public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); LocationService (Client) The connection is single threaded as I mentioned before. The isThisIt() method is similar to isEDT() and indicates if the current thread is the one managed by the EasyThread if not we use run(Runnable) which invokes the target Runnable on the EasyThread similarly to callSerially
  • 14. public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); float dir = lastKnownLocation.getDirection(); if(ll == lon && lt == lat && dir == direction) { return; } long time = System.currentTimeMillis(); if(time - lastUpdateTime < MAX_UPDATE_FREQUENCY) { return; } lastUpdateTime = time; lon = ll; lat = lt; direction = dir; try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos);) { dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE); String token = Preferences.get("token", null); LocationService (Client) If the values didn't change since last update so we do nothing
  • 15. public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); float dir = lastKnownLocation.getDirection(); if(ll == lon && lt == lat && dir == direction) { return; } long time = System.currentTimeMillis(); if(time - lastUpdateTime < MAX_UPDATE_FREQUENCY) { return; } lastUpdateTime = time; lon = ll; lat = lt; direction = dir; try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos);) { dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE); String token = Preferences.get("token", null); LocationService (Client) We don't update too much, there is a chance we'll miss an update here but it's probably not a deal breaker if a user didn't move much
  • 16. public void sendLocationUpdate() { if(!et.isThisIt()) { et.run(() -> sendLocationUpdate()); return; } if(lastKnownLocation != null) { double lt = lastKnownLocation.getLatitude(); double ll = lastKnownLocation.getLongitude(); float dir = lastKnownLocation.getDirection(); if(ll == lon && lt == lat && dir == direction) { return; } long time = System.currentTimeMillis(); if(time - lastUpdateTime < MAX_UPDATE_FREQUENCY) { return; } lastUpdateTime = time; lon = ll; lat = lt; direction = dir; try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos);) { dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE); String token = Preferences.get("token", null); LocationService (Client) We create a ByteArrayOutputStream into which we construct the message that we receive on the server with the header, location etc.
  • 17. try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos);) { dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE); String token = Preferences.get("token", null); dos.writeShort(token.length()); for(int iter = 0 ; iter < token.length() ; iter++) { dos.writeByte((byte)token.charAt(iter)); } dos.writeDouble(lat); dos.writeDouble(lon); dos.writeFloat(dir); dos.writeDouble(1); dos.writeByte(0); dos.flush(); send(bos.toByteArray()); } catch(IOException err) { Log.e(err); } } } @Override protected void onClose(int i, String string) { Log.p("Connection closed! Error... " LocationService (Client) I currently hardcoded a 1 kilometer search radius and defined explicitly that we aren't in taxi hailing mode
  • 18. try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos);) { dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE); String token = Preferences.get("token", null); dos.writeShort(token.length()); for(int iter = 0 ; iter < token.length() ; iter++) { dos.writeByte((byte)token.charAt(iter)); } dos.writeDouble(lat); dos.writeDouble(lon); dos.writeFloat(dir); dos.writeDouble(1); dos.writeByte(0); dos.flush(); send(bos.toByteArray()); } catch(IOException err) { Log.e(err); } } } @Override protected void onClose(int i, String string) { Log.p("Connection closed! Error... " LocationService (Client) One line to actually send the binary data, it would be similar with text data with the exception of parsing overhead. The IOException isn't likely as this is a RAM based stream
  • 19. try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos);) { dos.writeShort(MESSAGE_TYPE_LOCATION_UPDATE); String token = Preferences.get("token", null); dos.writeShort(token.length()); for(int iter = 0 ; iter < token.length() ; iter++) { dos.writeByte((byte)token.charAt(iter)); } dos.writeDouble(lat); dos.writeDouble(lon); dos.writeFloat(dir); dos.writeDouble(1); dos.writeByte(0); dos.flush(); send(bos.toByteArray()); } catch(IOException err) { Log.e(err); } } } @Override protected void onClose(int i, String string) { Log.p("Connection closed! Error... " LocationService (Client) The IOException isn't likely as this is a RAM based stream
  • 20. @Override protected void onClose(int i, String string) { Log.p("Connection closed! Error... " + "trying to reconnect in 5 seconds"); UITimer.timer(5000, false, () -> connect()); } @Override protected void onMessage(String string) { } @Override protected void onMessage(byte[] bytes) { try { DataInputStream dis = new DataInputStream( new ByteArrayInputStream(bytes)); short response = dis.readShort(); int size = dis.readInt(); for(int iter = 0 ; iter < size ; iter++) { long id = dis.readLong(); User car = cars.get(id); if(car == null) { car = new User(). id.set(id). latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). LocationService (Client) Here we receive the messages sent from the server specifically driver search results
  • 21. @Override protected void onClose(int i, String string) { Log.p("Connection closed! Error... " + "trying to reconnect in 5 seconds"); UITimer.timer(5000, false, () -> connect()); } @Override protected void onMessage(String string) { } @Override protected void onMessage(byte[] bytes) { try { DataInputStream dis = new DataInputStream( new ByteArrayInputStream(bytes)); short response = dis.readShort(); int size = dis.readInt(); for(int iter = 0 ; iter < size ; iter++) { long id = dis.readLong(); User car = cars.get(id); if(car == null) { car = new User(). id.set(id). latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). LocationService (Client) We store User instances in a Map where the user ID is the key. This saves us from sending duplicate carAdded events and allows us to just mutate the User properties which other code can observe using the builtin listeners in properties
  • 22. long id = dis.readLong(); User car = cars.get(id); if(car == null) { car = new User(). id.set(id). latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). direction.set(dis.readFloat()); cars.put(id, car); User finalCar = car; callSerially(() -> carCallback.carAdded(finalCar)); } else { car.latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). direction.set(dis.readFloat()); } } } catch(IOException err) { Log.e(err); } } protected void onError(Exception e) { Log.e(e); } LocationService (Client) Notice that this code is running on the WebSocket thread so events need to go back into the EDT to prevent potential issues
  • 23. long id = dis.readLong(); User car = cars.get(id); if(car == null) { car = new User(). id.set(id). latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). direction.set(dis.readFloat()); cars.put(id, car); User finalCar = car; callSerially(() -> carCallback.carAdded(finalCar)); } else { car.latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). direction.set(dis.readFloat()); } } } catch(IOException err) { Log.e(err); } } protected void onError(Exception e) { Log.e(e); } LocationService (Client) This is really important, we need handle errors properly in a WebSocket application otherwise a failure can leave us without a connection
  • 24. latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). direction.set(dis.readFloat()); cars.put(id, car); User finalCar = car; callSerially(() -> carCallback.carAdded(finalCar)); } else { car.latitude.set(dis.readDouble()). longitude.set(dis.readDouble()). direction.set(dis.readFloat()); } } } catch(IOException err) { Log.e(err); } } protected void onError(Exception e) { Log.e(e); } } public static interface CarAdded { void carAdded(User driver); } } LocationService (Client) The callback interface is trivial, it's mostly used as a lambda expression in the code… And that’s it for the location service…