Die Netzwerkprogrammierung hat ein paar Besonderheiten.
- Es ist erforderlich, die Berechtigung dafür vom Handy-Besitzer zu holen.
- Bei einer Netzwerkanfrage blockiert das Programm, bis der Partner
reagiert. In dieser Zeit kann die GUI nicht bedient werden. Darum wird
die Netzwerkkomponente in einen Thread gesetzt.
- Einige Tests, die auf dem Emulator hartnäckig scheiterten, funktionierten
auf einem echten Smartphone tadellos.
Um Erlaubnis bitten
Damit ein Programm im Netzwerk arbeiten darf, muss in der Datei
AndroidManifest.xml die Erlaubnis
für INTERNET hinterlegt sein.
<uses-permission android:name="android.permission.INTERNET"/>
Dieser Eintrag muss außerhalb des application-Tags sein, am besten
gleich zu Anfang der Datei.
Prüfe auf Netzwerkfähigkeit
Mit der folgenden Methode wird geprüft, ob das Programm auf das Netzwerk
zugreifen kann.
public boolean isNetAvailable() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVER);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null && ni.isConnectedOrConnecting();
}
Für diese Prüfung ist neben der INTERNET-Permission auch
die Permission ACCESS_NETWORK_STATE erforderlich:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
HTTP-Client
HTTP-POST mit Thread
Das folgende Beispiel zeigt eine HTTP-POST-Sendung von Android aus.
Damit der UI-Thread nicht blockiert, wird der Netzwerkverkehr in einen eigenen
Thread ausgelagert. Um die Ergebnisse auf der Oberfläche darzustellen, wird
runOnUiThread verwendet, da der Hintergrund-Thread selbst keinen
Zugriff darauf hat.
public void postText(final String text) { // final, da vom Thread ausgelesen
// Weil Netzwerkoperationen blockieren können, müssen sie in einen
// anderen Thread als die Activity
new Thread(new Runnable() {
@Override
public void run() {
try {
// Parameter soll gepostet werden. Dazu muss er URL-Encoded werden,
// damit Leerzeichen und Umlaute verschwinden.
// feld= entspricht dem input einer HTML-Form
String param = "feld="+ URLEncoder.encode(text, "UTF-8");
URL url = new URL("http://www.willemer.de/echoString"); // URL ist ein Dummy! Bitte anpassen!
HttpURLConnection connect = (HttpURLConnection) url.openConnection();
connect.setDoOutput(true);
connect.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// Länge der Message: Achtung UTF-8 erzwingt getBytes
connect.setFixedLengthStreamingMode(param.getBytes().length);
OutputStreamWriter out = new OutputStreamWriter(connect.getOutputStream());
out.write(param);
out.flush();
out.close();
InputStream is = connect.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String zeile;
while ((zeile = br.readLine())!= null) {
sb.append(zeile);
sb.append("\n");
}
// wird in anderem Runnable benötigt, also final
final String antwort = sb.toString().trim();
// Zugriff auf das TextView der Activity
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(antwort);
}
});
// Aufräumen!
is.close();
connect.disconnect();
} catch (UnsupportedEncodingException e) {
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
}).start(); // starte im Background
}
Service
Für die Kommunikation wird ein eigener Service erstellt. Das wird über das
Menü File|New|Service|Service
erreicht. Als Namen vergeben wir NetzwerkService.
Die Implementierung enthält einen Thread, der die Netzwerkaktion durchführt.
Der Thread meldet sich nach getaner Arbeit bei der Activity zurück.
package de.willemer.phpclient;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
public class NetzwerkService extends Service {
// private static final String url ="http://10.0.2.2/gast.php";
private final IBinder netzwerkBinder = new NetzwerkBinder();
public NetzwerkService() {
}
// Wir bauen eine eigene Binder-Klasse
public class NetzwerkBinder extends Binder {
public NetzwerkService getService() {
return NetzwerkService.this;
}
public void senden(final Handler threadHandler, String msg) {
Thread thread = new Thread() {
@Override
public void run() {
long error = 0;
// error = dieEigentlicheSendeMethode();
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putLong("stauId", error);
msg.setData(bundle);
threadHandler.sendMessage(msg);
}
};
thread.start();
}
}
@Override
public IBinder onBind(Intent intent) {
return netzwerkBinder;
}
}