Android apps connected to Delphi DataSnap Server

Categories:Android, DelphiTags: , , ,

On the following video I’m showing how you can create DataSnap REST Server in Delphi, expose server methods and call them from an Android application. The video shows all the steps to create the server and the Android application.


This is a short recap of the video.

In order to have other platforms connecting and interacting with your DataSnap Server you need to enable the REST Interface, and for mobile platforms you can use the DataSnap Connectors that generate proxy classes for Android, BlackBerry, Windows Phone and iOS. In the video I’m showing how to create the Server, let’s take a look at the Server Method implementation.

The first server method called InsertCountry, connect on my InterBase database and add a new record to the Country table, see the implementation below:

function TServerMethods1.InsertCountry(Country, Currency: String;
  out Error: String): Boolean;
var
  Comm: TDBXCommand;
begin

  Result := False;

  DBConn.Open;
  Comm := DBConn.DBXConnection.CreateCommand;
  Comm.CommandType := TDBXCommandTypes.DbxSQL;
  Comm.Text :=
    Format('Insert Into Country (COUNTRY, CURRENCY) Values ( ''%s'', ''%s'')',
    [Country, Currency]);

  if not Comm.IsPrepared then
    Comm.Prepare;

  try
    Comm.ExecuteUpdate;
    Comm.Free;
    Result := True;
  except on E: Exception do
    Error := E.Message;
  end;

end;

The second server method is called GetCountries, and returns all the records I have in the COUNTRY table on my InterBase database. This method returns a DBXReader and DataSnap will convert this automatically to JSON at the moment the Android app calls this method, but since we will use the new DataSnap Connector to generate the proxy class, we won’t need to handle the JSON object and I will explain that after.

The following code represents the GetCountries implementation.

function TServerMethods1.GetCountries: TDBXReader;
var
  Comm: TDBXCommand;
begin

  DBConn.Open;
  Comm := DBConn.DBXConnection.CreateCommand;
  Comm.CommandType := TDBXCommandTypes.DbxSQL;
  Comm.Text := 'Select * from Country';

  if not Comm.IsPrepared then
    Comm.Prepare;

  Result := Comm.ExecuteQuery;

end;

The next step is to create the proxy class for Android using the DataSnap connectors, which is a new feature in Delphi XE2. The generation can be done through command line or via HTTP request on your DataSnap server, and in the video I’m showing how to do that.

The proxy generator generates only the DSProxy.java, all the other files part of the DataSnap Connectors are the representation of DataSnap Framework in Java, for example you won’t need to parse the DBXReader as JSON object in Java, just because we have the DBXReader class in Java and it parses the JSON object for you.

The first step to create a REST connection with your DataSnap Server, which will give me a instance of DSRESTConnection. If your DataSnap Server requires authentication you can use the methods SetUserName and SetPassword to define the credentials.

	private DSRESTConnection getConnection() {
		DSRESTConnection conn = new DSRESTConnection();
		conn.setHost("192.168.254.128");
		conn.setPort(8080);
		return conn;
	}

Now, let’s take a look and see how to execute the server methods, starting with the InsertCountry method as you can see in the following code.

After instantiation of the DSRESTConnection, we pass the REST connection object to the TServerMethods1′s instance, which is the client representation of TServerMethods1 on the server, and from there just call InsertCountry.

Since InsertCountry returns Boolean and also the Error message parameter is passed as reference, InsertCountry methods will return a InsertCountryReturns, which is a static class with two parameters: error that represent the error message and returnValue which represent the value return by InsertCountry.

protected void Insert() {

	DSRESTConnection conn = getConnection();

	TServerMethods1 sm = new TServerMethods1(conn);

	try {
		InsertCountryReturns ret;
		ret = sm.InsertCountry(editCountry.getText().toString(), editCurrency.getText().toString(), "");

		if ( ! ret.returnValue ) {
			System.out.println(ret.error);
		}

	} catch (DBXException e) {
		e.printStackTrace();
	}

	// Hide keyboard
	InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
	imm.hideSoftInputFromWindow(editCountry.getWindowToken(),0);

}

The next method is GetCountries. We start as before by getting the DSRESTConnection instance. The GetCountries method returns a DBXReader and the way we work with the DBXReader class in Java is very similar the way we work in Delphi, use the Next method to interact through the result, and getValue/GetAsXXXXX to get the column value. See the following code:

protected void Refresh() {

	DSRESTConnection conn = getConnection();

	TServerMethods1 sm = new TServerMethods1(conn);

	TDBXReader reader;
	try {
		reader = sm.GetCountries();

		ArrayList COUNTRIES = new ArrayList();

		while (reader.next()) {
			COUNTRIES.add(reader.getValue("COUNTRY").GetAsString());
		}

		// Add the COUNTRIES array in to the list view
		list.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, COUNTRIES));

	} catch (DBXException e) {
		e.printStackTrace();
	}

}

This is just a short tutorial explaining how to use DataSnap Connector with Android, take some time and watch the video where I’m going through more details.

The source code is available for download here and download the video from here.

21 Responses to Android apps connected to Delphi DataSnap Server

  1. Reply Michael Justin says:

    COUNTRIES.add(reader.getValue(“COUNTRY”).GetAsString()) looks a little overcomplicated when compared with typical JDBC result set processing in Java. Maybe a future version of DataSnap will allow more intuitive code like reader.getString(“field”) … ?

  2. Reply Omar Zelaya says:

    Hi,

    I’m doing some tests on Android to call a DataSnap server method that
    returns a simple class.

    Delphi Side:
    TPrueba = class
    private
    FUnString : string;
    public
    published
    property UnString : string read FUnString write FUnString;
    end;

    Java Side:

    private class TPrueba {
    public String UnString;

    }

    With the following Datasnap server method:

    function RetornaEstructura(Value : string) : TPrueba;

    When I generate the java.android proxy the method returns a TJSONObject.

    1. Is the Java class definition ok to match the Delphi one and be able parse
    it?
    2. I have tried using the Google.GSon library to parse the TJSONObject with
    no success. it is possible?
    I get a empty Prueba when I call Prueba = g.fromJson(JSonObj.toString(),
    Prueba.getClass()); or am I doing it wrong?
    3. Is there another way to parse the TJSONObject and load into the
    TPrueba Java class?

    Thanks in advance,

    Omar Zelaya

  3. Reply statik0 says:

    Hi, I need to develop an Android application that connects to an Delphi application using a web service . Some ideas ?? Help me please !!!

  4. Reply Khan says:

    Where can I download this sample source code on Delphi and Java.

    Thank you.

  5. Reply Anagnostes says:

    What should be the setHost and setPort of the getConnection() funcion when you deploy the WebService as isapi dll?

    I get “Host may not be null” all the time.

    Thank you

    • Reply Andreano Lanusse says:

      setHost should be IP or hostname of the machine running the DataSnap Server and port should be 8080, unless you changed the default

      • Reply Anagnostes says:

        With a dll in an IIS server with the 8080? I thought the port was 80 as HTTP in IIS.

        With IP and port 8080 doesn’t work. I compile the dll, put it in a server with other ISAPIs and no way i can’t get a connection in Java.

        with http://192.168.2.5/TestRest.dll i get the default DataSnap REST Project webpage.

        I don’t know if i’m doing something wrong.

        Thank you very much… that’s a record time answer!

  6. Reply Andreano Lanusse says:

    In IIS will be port 80 by default and try to call some server method, just http://192.168.2.5/TestRest.dll won’t do anything

    • Reply Anagnostes says:

      Finnally got it:

      conn.setHost(“192.168.2.5″);
      conn.setPort(80);
      conn.setUrlPath(“/TestRest.dll”);

      Thanks

  7. Reply Remmie Ran says:

    Hi,
    I followed your example to connect to datasnap and create an android app but it is not working on the android side. for some reason I does not post back to the table or refresh the data. It does work if i use a web page but not from eclipse. any Ideas?

    • Reply Andreano Lanusse says:

      @Remmie I’m not understanding what is the problem, can you please clarify.

      • Reply Remmie Ran says:

        Andreano, I think is the eclipse system on my PC It just will not “talk” with the REST Server for some reason. calling the same address from a web browser works. but not from the Android emulator. I am trying to do the same in RADPHP and having problems with the DBXReader. I do not know how to access it. ??

  8. Reply giovanni says:

    in the first example InsertCountry ther is Comm.Free,
    in the second example GetCountries no. Why ?

    Thanks

    • Reply Andreano Lanusse says:

      Giovanni, because on the second one I return the cursor through the TDBXReader, as the server finish to send the cursor to the client side it will be automatically destroyed by the server.

  9. Reply Sergio Kawahara says:

    Andreano, primeiramente quero parabeniza-los pelos post, muito util para a comunidade, gostaria de saber como posso fazer para compartilhar a function getConnection() com outras class, sem a precisar refazer a function em cada class, fazendo apenas a chamada, já tentei assim:
    ClassConexao Conexao = new ClassConexao();
    DSRestConnection conn = Conexao.getConnection();
    Mas não funciona, se puder ajudar fico muito grato

    Sergio Kawahara

  10. Reply dison says:

    Hello Lanusse im getting a error “incorrect type in dbxvalue” if the table has a field of data type integer

    when i call in my code
    COUNTRIES.add(reader.getValue(“ID”).GetAsInt16());

    if i call using
    COUNTRIES.add(reader.getValue(“ID”).GetAsString()); i have the same error

    How fill my adapter with a field with data type int in my table

    Thanks

  11. Reply João Carlos says:

    Andreano, gostaria de parabenizá-lo pelo excelente tutorial.
    Estou começando a desenvolver em Android agora e já consegui implementar o codigo sem problemas na API 10 (Android 2.3.3), infelizmente não consego em nenhume API lançada após a 10. Já quebrei a cabeça bastante mas não encontro solução. Gostaria de lhe pedir uma ajuda para esse caso. Fico muito grato.

    Obrigado

  12. Reply Clederson says:

    você tem essa aula em Português?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>