Warning: Undefined variable $html in /customers/9/6/e/chocofant.dk/httpd.www/2010/php/MessageController.php on line 98

Android 2.0.1 - GPS locator

Lately I've spent some time fiddling around with the Android framework. Here is activity code for a GPS locator. Should you get lost somewhere, it can show you your current location.

The application is pieced together based on examples I found on the Internet. Unlike a lot of the sample code on the net, this code is based on the Android 2.0.1 framework
public class GPSLocator extends MapActivity {
private LocationManager locationManager;
private LocationProvider locationProvider;
private LocationListener locationListener;
private Location currentLocation;
private MyLocationOverlay myLocationOverlay;
private MapController mapController;
private MapView mapView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// Set properties for the mapView
mapView = (MapView)findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(true);

// Set zoom factor
mapController = mapView.getController();
mapController.setZoom(10);

// Get most recent location from built-in location provider
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
currentLocation = locationManager.getLastKnownLocation("gps");

// Get fix updates every 10 sec. or if current location is at least 50 m. from last fix
locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10000, // 10 sec.
50, // meters.
locationListener);

// Call method to draw marker
updateOverlay(currentLocation);
}

@Override
protected boolean isRouteDisplayed() {
return false;
}

// Draws a marker on a map overlay and centers the new location
protected void updateOverlay(Location location)
{
// Clear old marker overlay
List overlays = mapView.getOverlays();
if(overlays.size() > 0)
{
for(Iterator it = overlays.iterator(); it.hasNext();)
{
it.next();
it.remove();
}
}

GeoPoint geoPoint = getGeoPoint(location);

// Get marker to draw
Drawable marker = getResources().getDrawable(R.drawable.marker);
marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());

// Create new overlay with marker at geoPoint
LocationItemizedOverlay overlay = new LocationItemizedOverlay(marker);
OverlayItem overlayItem = new OverlayItem(geoPoint, "Location", "You are here");
overlay.addOverlay(overlayItem);

// Add overlay to mapView and center to geoPoint
mapView.getOverlays().add(overlay);
mapView.getController().animateTo(geoPoint);
mapView.postInvalidate();
}

// Create a GeoPoint from a Location object
protected GeoPoint getGeoPoint(Location location)
{
if(location == null)
{
return null;
}
Double lat = location.getLatitude()*1E6;
Double lng = location.getLongitude()*1E6;
return new GeoPoint(lat.intValue(), lng.intValue());
}

// Inner Location Listener class definition
protected class MyLocationListener implements LocationListener
{
@Override
public void onLocationChanged(Location location) {
TextView locationLayout = (TextView)findViewById(R.id.current_location);
locationLayout.setText("Location changed : Lat: " + location.getLatitude() +
" Lng: " + location.getLongitude());
updateOverlay(location);
}

// Omitted empty override methods
}

// Map overlay on which the location marker is drawn
protected class LocationItemizedOverlay extends ItemizedOverlay
{
private List overlays;

public LocationItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
overlays = new ArrayList();
}

@Override
protected OverlayItem createItem(int i) {
return overlays.get(i);
}

@Override
public int size() {
return overlays.size();
}

public void addOverlay(OverlayItem overlay) {
overlays.add(overlay);
populate();
}
}
}

For this to work you need to add "android.permission.ACCESS_FINE_LOCATION" and "android.permission.INTERNET" to your Manifest.xml and to use google maps you need a Api key.


Model-view-controller pattern

The pattern seperates the data presentation from domain logic.
The model is some form of domain object. The view generates the UI. And the controller handles requests from the view and calls the model on behalf of the view. When the model state has changes it notifies the view so it can update itself.
By decoupling view and model you have the flexibility to use various UI types with the same model and testing the model without concern for the UI.

Here is an example using the observer pattern for notification.
In C# events and delegates could be used instead.

All 3 parts implement an interface that way tight coupling is avoided.
// Model Interface
public interface IModel
{
String Data { get; set; }
void AddObserver(IView view);
void RemoveObserver(IView view);
void Notify();
}

// View Interface
public interface IView
{
void UpdateView(IModel model);
}

// Controller Interface
public interface IController
{
void ChangeData(string input);
IModel Model { get; set; }
IView View { get; set; }
}

The concrete class implementations
// Model class
public class Model : IModel
{
List<IView> observers = new List<IView>();

private string data = string.Empty;
public string Data
{
get{ return data; }
set
{
data = DateTime.Now.ToString() + ": " + value;
this.Notify();
}
}

public void AddObserver(IView view)
{
observers.Add(view);
}

public void RemoveObserver(IView view)
{
observers.Remove(view);
}

// Notify observers about state change
public void Notify()
{
foreach (IView view in observers)
{
view.UpdateView(this);
}
}
}

// View class
// Code is edited for display, won't compile
public class View : IView
{
// Get concrete Controller and Model class
private IController controller = MyMVCFactory.GetInstance("Controller");
private IModel model = MyMVCFactory.GetInstance("Model");
public View()
{
SetupControllerModel(controller, model);
this.UpdateView(model);
}

private void SetupControllerModel(IController controller, IModel model)
{
if (this.model != null)
{
// Make sure the view isn't observing multiple times
this.model.RemoveObserver(this);
this.model = model;
this.controller = controller;
this.controller.View = this;
this.controller.Model = this.model;
this.model.AddObserver(this);
}
}

// Display data from model
public void UpdateView(IModel model)
{
label.Text = model.Data;
}

// Call controller to request change to model data
private void button1_Click(object sender, EventArgs e)
{
controller.ChangeData(textBox.Text);
}
}

// Controller class
public class Controller : IController
{
private IView view;
private IModel model;

public Controller() { }

public void ChangeData(string input)
{
model.Data = input;
}

public IModel Model
{
get { return this.model; }
set { this.model = value; }
}

public IView View
{
get { return this.view; }
set { this.view = value; }
}
}

The view calls the controller to ask for a change in the model when a user clicks the button. The text argument from an text box is passed to the model. The model prepends a timestamp to the data and notifies the view about the change. Lastly the view displays the edited data from the model on a label.


Send data from one winform to another

We have a form (A) with a text box and a button
When I click the button a new form (B) is opened.
This also has a text box and a button.
In form B's text box I can write some text which will be displayed in form A's text box when I'm done.

The method for the form A button click event looks like this:
private void formA_button_Click(object sender, EventArgs e)
{
FormB formB = new FormB();
// subscribe to FormB SendData event and add callback method
formB.SendData += new FormB.SendDataHandler(formB_ButtonClicked);
formB.Show();
}

Definition of the SendData callback method.
private void formB_ButtonClicked(object sender, DataEventArgs e)
{
// Display data from form B in form A's text box
// Data is passed along in the DataEventArgs property Data
formA_TextBox.Text = e.Data;
}

On form B things look like this:
// The event handler (delegate)
public delegate void SendDataHandler(object sender, DataEventArgs e);
// The event
public event SendDataHandler SendData;

// The args initialization could also
// be placed in the OnSendData method,
// but I put it here for clarity
private void formB_button_Click(object sender, EventArgs e)
{
string data = formB_textBox.Text;
DataEventArgs args = new DataEventArgs(data);
OnSendData(args);
}

// Fire event from this method
protected void OnSendData(DataEventArgs args)
{
if (SendData != null)
{
SendData(this, args);
}
}

And last the definition of the inherited DataEventArgs class
public class DataEventArgs : EventArgs
{
private string data;

public DataEventArgs(string data)
{
this.data = data;
}

public string Data
{
get { return data; }
}
}

This is it, this is basically how you send data from one form to another.
An alternate way of passing data would to let form (B) have a reference to form A which then implement a public text box setter property.


Flexible XmlHttpRequest function

In AJAX the XmlHttpRequest object is used for asynchronous communication between client and server.
Here is an example of a "generic" XmlHttpRequest function for requests. The purpose of the generic aspect of this function is to limit code duplication.
Often your make many types of requests and the responses should be posted in various places in the page.
Instead of creating a function for each request type, we can use the same function for all.

This is the request function
function SendRequest(url, params, targetId)
{
xmlHttpObject = GetXmlHttpObject();

if(xmlHttpObject==null)
{
alert("Your browser does not support XMLHTTP");
return;
}

// POST is used instead of GET to send request
// but it is irrelevant for the example
xmlHttpObject.open("POST", url, true);
xmlHttpObject.onreadystatechange = function()
{
if(xmlHttpObject.readyState == 4)
{
var response = xmlHttpObject.responseText;

// targetId specifies where to post the response
document.getElementById(targetId).innerHTML = response;
}
}

xmlHttpObject.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlHttpObject.setRequestHeader("Content-length", params.length);
xmlHttpObject.setRequestHeader("Connection", "close");
// Pass parameters
xmlHttpObject.send(params);
}

Help function to get a XmlHttpRequest object
function GetXmlHttpObject()
{
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
return new XMLHttpRequest();
}

if (window.ActiveXObject)
{
// code for IE6, IE5
return new ActiveXObject("Microsoft.XMLHTTP");
}
return null;
}

Here is how you can call the request function, url, parameters, and target element must be set.
function updateList(userId)
{
var url = "./php/RequestHandler.php";
var params = "req=updatelist&userid="+userId;
var targetId = "content";
SendRequest(url, params, targetId);
}

function getList()
{
var url = "./php/RequestHandler.php";
var params = "req=getlist";
var targetId = "side";
SendRequest(url, params, targetId);
}


List<T> and generic delegates

Here is few example of how you can do operations on generic lists with generic delegates and anonymous methods. The reason for using these features is to compact your code, reduce creation time.
Many coders also see it as a way of writing more elegant code.
I think it comes from the fact that is a bit difficult to write and a lot harder to read.
IMO it is not elegant code, just a blatant way of trying to say you are a good coder (eh.. I guess that's make me one myself).
However I prefer code that is easily read anytime.

But let's have a look at some code instead of dwelling on my ranting.
First we instatiate a list with some people
List<Person> people = new List<Person>();
people.Add(new Person(50, "Fred"));
people.Add(new Person(8, "John"));
people.Add(new Person(26, "Alice"));
people.Add(new Person(14, "Bob"));
people.Add(new Person(25, "Mark"));
people.Add(new Person(6, "Sue"));

The ForEach method takes a Action<T> delegate as parameter.
In this case the action is just printing name and age of each person.
We didn't have to assign the DisplayAction, we could have passed the Display method to the ForEach method directly.
delegate void DisplayAction(Person p);
DisplayAction displayAction = Display;

// Display list
people.ForEach(displayAction);

public void Display(Person p)
{
Console.WriteLine(String.Format("{0} {1}", p.name, p.age));
}

The FindAll method takes a Predicate<T> delegate as parameter.
The predicate defines a criteria for the search.
// Get a list of people under 25
List<Person> young = people.FindAll(UnderTwentyFive);

public bool UnderTwentyFive(Person p)
{
return p.age < 25;
}

// Display new list using an anonymous method instead of Action<T> delegate
young.ForEach(delegate(Person p)
{
Console.WriteLine(String.Format("{0} {1}", p.name, p.age));
});

Sort the list using a Comparison<T> delegate, again we hand in the compare method directly
people.Sort(CompareNames);

public int CompareNames(Person a, Person b)
{
return p1.name.CompareTo(p2.name);
}

// Display people list using an anonymous method
people.ForEach(delegate(Person p)
{
Console.WriteLine(String.Format("{0} {1}", p.name, p.age));
});

Here is used anonymous methods for sorting by age and for displaying the list
people.Sort(delegate(Person p1, Person p2)
{
return p1.age.CompareTo(p2.age);
});

people.ForEach(delegate(Person p)
{
Console.WriteLine(String.Format("{0} {1}", p.name, p.age));
});

And the person class definition
public class Person
{
public int age;
public string name;

public Person(int age, string name)
{
this.age = age;
this.name = name;
}
}



| Next page ->