Cient-Server-Kommunikation von Android (Client) zu Java (Server) via http

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.

Serverseitige Implementierung

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:

  • mysql-connector-java-5.1.29-bin.jar
  • jetty-server-9.1.1.v20140108.jar
  • jetty-util-9.1.1.v20140108.jar
  • servlet-api-3.1.jar
  • jetty-http-9.1.1.v20140108.jar
  • jetty-io-9.1.1.v20140108.jar

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) {
 
	    }
	  }
 
}

Clientseitige Implementierung

Im Manifest des Android-Projekts muss folgende Berechtigung vergeben werden:

<uses-permission android:name="android.permission.INTERNET" />

Client-Layout Das Layout des Client-Programms ist rechts zu sehen. Folgende Ids sind vergeben:

  • Button: buttonVerbinden
  • ListView: liste


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);
	}
 
 
 
}
Drucken/exportieren
QR-Code
QR-Code programmieren:java:android:httpclient:start (erstellt für aktuelle Seite)