Im folgenden wird das Gerüst der Kommunikation anhand der wichtigsten Code-Fragmente beschrieben. Rechts sehen Sie eine Übersicht der wesentlichen Komponenten. Der Client (Android-Handy) schickt einen http-GET-Request an den Server. Dieser schickt eine strichpunktseparierte Liste zurück, die der Client in einer ListView anzeigt.
Auf dem Server werden die jar-Dateien der Jetty-Bibliothek in den Klassenpfad aufgenommen. Für die Jetty-Version 9.1.1 sind dies folgende Jars:
Die main-Methode instanziert ein MyServer-Objekt:
import server.MyServer; public class Main { public static void main(String[] args) { /** * Webserver instanzieren und starten */ MyServer server = new MyServer(); } }
Dieses wiederum instanziert und startet einen Embedded Jetty-Webserver, der auf Port 8080 horcht:
import org.eclipse.jetty.server.Server; public class MyServer { public MyServer(){ /** * Instanziert einen Jetty-Webserver, der später auf Port 8080 horchen soll */ Server server = new Server(8080); /** * Bei jedem Request wird vom Webserver die handle-Methode der Handler-Klasse MyHandler aufgerufen. */ server.setHandler(new MyHandler()); try { /** * Starten des Webservers */ server.start(); server.join(); } catch (Exception e) { e.printStackTrace(); } } }
Jeder http-Request führt zur Aufruf der Methode MyHandler.handle in einem eigenen Thread. Diese Methode gibt über das Response-Objekt abhängig vom Wert des per GET-Request übergebenen do-Parameters eine strichpunktseparierte Liste an den Client zurück:
import java.io.IOException; import java.util.Calendar; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; public class MyHandler extends AbstractHandler { @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); baseRequest.setHandled(true); /** * Je nach Wert des GET-Parameters do sollen unterschiedliche Daten zurückgegeben werden */ String befehl = request.getParameter("do"); String antwort = ""; switch (befehl) { case "getteilnehmer": antwort = getTeilnehmer(); break; default: break; } response.getWriter().println(antwort); } private String getTeilnehmer() throws Exception { String antwort = Calendar.getInstance().getTime().toString() + ";"; // // antwort += "Martin Pabst;Regina Jasper-Loreck;Max Muster;Frieda Fleißig"; // // System.out.println(antwort); // // return antwort; try { // This will load the MySQL driver, each DB has its own driver Class.forName("com.mysql.jdbc.Driver"); // Setup the connection with the DB connect = DriverManager.getConnection("jdbc:mysql://localhost/dbkurse", "root", null); // Statements allow to issue SQL queries to the database statement = connect.createStatement(); // Result set get the result of the SQL query resultSet = statement .executeQuery("select * from teilnehmer"); // writeResultSet(resultSet); while (resultSet.next()) { String name = resultSet.getString("Name"); String vorname = resultSet.getString("Vorname"); antwort = antwort + name + " " + vorname + ";"; } } catch (Exception e) { throw e; } finally { close(); } return antwort; } private void close() { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connect != null) { connect.close(); } } catch (Exception e) { } } }
Im Manifest des Android-Projekts muss folgende Berechtigung vergeben werden:
<uses-permission android:name="android.permission.INTERNET" />
Das Layout des Client-Programms ist rechts zu sehen. Folgende Ids sind vergeben:
Hier der Code der MainActivity:
import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private ArrayAdapter<String> listAdapter; // Hält die Daten des ListView @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * Im ListView wird eine - initial leere - Liste von Strings angezeigt: */ ArrayList<String> aList = new ArrayList<String>(); ListView liste = (ListView)findViewById(R.id.liste); listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1 , aList); liste.setAdapter(listAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } /** * * Ereignishandler für Klick auf den Button "Verbinden": * * @param view */ public void verbinden(View view){ /** * Der Http-Request ist blockierend. Damit er nicht die GUI lahmlegt, * muss er in einem eigenen Thread ausgeführt werden: */ RetrieveHttpTask task = new RetrieveHttpTask(listAdapter); task.execute(); } }
Da der Http-Request blockierend ist, darf er nicht im UI-Thread ausgeführt werden. Wir benutzen daher einen AsyncTask, um ihn in einem separaten Thread zu starten. AsyncTask stellt darüber hinaus die Methode opPostExecute bereit, die nach Ende von doInBackground automatisch aufgerufen wird und garantiert in UI-Thread läuft, so dass darin wieder GUI-Ausgaben stattfinden dürfen:
package com.example.webclient; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.os.AsyncTask; import android.util.Log; import android.widget.ArrayAdapter; public class RetrieveHttpTask extends AsyncTask<String, Void, String> { /** * ArrayAdapter zur Ausgabe der Namen in der ListView auf der GUI */ private ArrayAdapter<String> ausgabe; public RetrieveHttpTask(ArrayAdapter<String> aliste){ this.ausgabe = aliste; } @Override protected String doInBackground(String... params) { String result = "Fehler!"; HttpClient httpclient = new DefaultHttpClient(); /** * Request-Objekt vorbereiten. 10.36.15.207 muss durch die Adresse * des Servers ersetzt werden. */ HttpGet httpget = new HttpGet("http://10.36.15.207:8080?do=getteilnehmer"); HttpResponse response; try { /** * Hier wird der Request ausgeführt. * Bem.: Der Aufruf blockiert, bis der Server antwortet. */ response = httpclient.execute(httpget); Log.i("Response",response.getStatusLine().toString()); HttpEntity entity = response.getEntity(); if (entity != null) { /** * Wir lesen die Antwort des Servers (ohne http-Header!) in * den StringBuilder total ein. */ InputStream instream = entity.getContent(); BufferedReader r = new BufferedReader(new InputStreamReader(instream, "UTF-8")); StringBuilder total = new StringBuilder(); String line; while ((line = r.readLine()) != null) { total.append(line); } instream.close(); result = total.toString(); } } catch (Exception e) { Log.i("Response-Exception", e.toString()); } /** * Nach den return wird automatisch onPostExecute im UI-Thread aufgerufen. */ return result; } @Override protected void onPostExecute(String result) { /** * Die einzelnen Namen werden der strichpunktseparierten Liste entnommen und * einzeln der ListView hinzugefügt: */ List<String> liste = Arrays.asList(result.split(";")); ausgabe.clear(); ausgabe.addAll(liste); ausgabe.notifyDataSetChanged(); super.onPostExecute(result); } }