Allgemein Android Java Tipps und Tricks Tutorials

Asynchrone WebRequests für Android

Hallo,

viel zu lange ist mein letzter Post her. Ich habe nun meine Ausbildung als Fachinformatiker für Anwendungsentwicklung abgeschlossen und somit wieder etwas mehr Zeit fürs Blogging.

Jeder Android Programmierer kennt es… Irgendwo benötigt man irgendwann irgendwelche Anfragen an einen Server oder WebService. Eigentlich ganz einfach… dachte ich mir zumindest, denn mit URL.openConnection(), wie im folgenden Listing, funktioniert es nicht auf anhieb.

URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();

Warum?

Android sieht vor das WebRequests in Asynchronen Threads gestartet und verarbeitet werden. Klingt kompliziert, ist es anfänglich auch aber wenn man sich dann eingearbeitet hat, kann man damit relativ gut arbeiten.
Hier ein Beispiel für eine Asynchrone WebRequest(Quelle):

class RequestTask extends AsyncTask<String, String, String>{
 
    @Override
    protected String doInBackground(String... uri) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpResponse response;
        String responseString = null;
        try {
            response = httpclient.execute(new HttpGet(uri[0]));
            StatusLine statusLine = response.getStatusLine();
            if(statusLine.getStatusCode() == HttpStatus.SC_OK){
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                response.getEntity().writeTo(out);
                responseString = out.toString();
                out.close();
            } else{
                //Closes the connection.
                response.getEntity().getContent().close();
                throw new IOException(statusLine.getReasonPhrase());
            }
        } catch (ClientProtocolException e) {
            //TODO Handle problems..
        } catch (IOException e) {
            //TODO Handle problems..
        }
        return responseString;
    }
 
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        //Do anything with response..
    }
}

Wie man schon erkennen kann, müsste man allerdings pro Request ein Handling für die Response integrieren.

Was sind eigentlich Asynchrone Abfragen?

Asynchrone Abfragen bzw. Asynchroner Code, sind Programmteile welche zur Laufzeit in einem einem anderen Thread mit einer anderen Priorität abgearbeitet werden.
Dies heißt, dass die Android-App ganz normal weiter benutzt werden kann, ohne dass auf die Antwort der Abfrage gewartet werden muss. (Gegenteil Synchrones Threading, was allerdings in der Praxis meiner Meinung nach keinen Sinn ergibt)

Asynchrone WebRequests in einfach

Geht das nicht einfacher? Das dachte ich mir auch, und deshalb habe ich folgende Code-Snippets geschrieben.

NetHelper.java

Über die Methode GET, werden die GET-Anfragen abgewickelt. Mit der Methode isNetworkAvailable() könnt ihr prüfen ob das Gerät mit dem Internet verbunden ist.

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
 
import java.util.Map;
 
/**
 * Created by julian on 19.06.15.
 */
public class NetHelper {
 
    /**
     * Startet eine GET-Request
     * @param url Die URL
     * @param CallBack Die Callback Funktion
     */
    public static void GET(String url, NetCallback CallBack)  {
        AsyncWebRequest request = new AsyncWebRequest(CallBack);
        request.execute(url);
    }
 
    public static void GET(String url, NetCallback CallBack, Map<String, String> Headers)  {
        AsyncWebRequest request = new AsyncWebRequest(CallBack);
        request.Headers = Headers;
        request.execute(url);
    }
 
    /**
     * Prüft ob eine Internetverbindung steht
     * @param context Der Context
     * @return boolean Falls verbunden true, andernfalls false  
     */
    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();
 
        return (networkInfo != null && networkInfo.isConnected());
    }
}

NetCallback.java

Dies ist die Klasse in welcher ihr die Response verarbeiten könnt sobald diese da ist (Wird durch AsyncWebRequest.java aufgerufen, daher auch NetCallback).

import android.content.Context;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
 
/**
 * Created by julian on 01.07.15.
 */
public abstract class NetCallback implements Callable<String> {
 
    public Context mContext = null;
 
    public NetCallback() {
 
    }
 
    public NetCallback(Context mContext) {
        this.mContext = mContext;
    }
 
    public Map<String, List<String>> responseHeaders = null;
 
    public void call(String data) {
 
    }
 
    @Override
    public String call() throws Exception {
        return null;
    }
}

AsyncWebRequest.java

Über diese Klasse werden die Abfragen abgewickelt.

import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
 
/**
 * AsyncWebRequest
 */
public class AsyncWebRequest extends AsyncTask<String, Integer, String> {
 
    public NetCallback CallBack = null;
    public Map<String, String> Headers = new HashMap<String, String>();
    public String output = "";
 
    public  AsyncWebRequest(NetCallback CallBack) {
        this.CallBack = CallBack;
    }
 
    @Override
    protected String doInBackground(String... uri) {
        final StringBuilder output = new StringBuilder();
        URLConnection connection = null;
        try {
            URL address = new URL(uri[0]);
            connection = address.openConnection();
            if (this.Headers.size() > 0) {
                for ( Map.Entry<String, String> entry : this.Headers.entrySet() ) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
 
            InputStream response = connection.getInputStream();
 
            BufferedReader reader = new BufferedReader(new InputStreamReader(response));
            String line = "";
 
            while ((line = reader.readLine()) != null) {
                output.append(line);
            }
            this.CallBack.responseHeaders = connection.getHeaderFields();
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.output = output.toString();
        publishProgress(100);
        return output.toString();
    }
    @Override
    protected void onProgressUpdate(Integer... integers) {
        this.CallBack.call(this.output.toString());
    }
 
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
    }
}

So, und wie funktioniert das jetzt?

Im Grunde müsst ihr die oben geschriebenen Snippets nicht weiter beachten und nur in euer Android Package hinzufügen.

Sobald ihr das getan habt, könnt Ihr in eurem Code wie folgt eine Asynchrone WebRequest abfeuern, sobald eine Response angekommen ist, wird die Methode call(String data) aufgerufen.

NetHelper.GET("http://example.com/", new NetCallback() {
    @Override
    public void call(String data) {
        // Eure verarbeitung der Daten
    }
});

Wenn ihr irgendwelche Header übergeben müsst, wie zum Beispiel Cookies, könnt ihr noch ein Array mit den Headern übergeben

// Erstelle Map mit Headern
Map<String, String> Headers = new HashMap<String, String>();
Headers.put("Cookie", "cookie1=Wert1; cookie2=Wert2");
 
NetHelper.GET("http://example.com/", new NetCallback() {
    @Override
    public void call(String data) {
        // Eure verarbeitung der Daten
    }
}, Headers);

Fazit

Mit diesen Klassen ist es deutlich einfacher und übersichtlicher WebRequests abzufeuern, vor allem da diese Asynchron verarbeitet werden.
Daher habe ich dies schon zu einem festen Bestandteil meines persönlichen Frameworks gemacht.

Lizenz

Creative Commons Lizenzvertrag
Android Asynchronous WebRequests von Julian Finkler ist lizenziert unter einer Creative Commons Namensnennung – Weitergabe unter gleichen Bedingungen 4.0 International Lizenz.
Beruht auf dem Werk unter https://www.developer-heaven.de/allgemein/asynchrone-webrequests-fuer-android.
Über diese Lizenz hinausgehende Erlaubnisse können Sie unter https://www.developer-heaven.de/ erhalten.

So, mehr brauche ich dazu eigentlich nicht schreiben, oder?

Fragen oder Anregungen? Immer her damit.

Nun heißt es für mich gute Nacht und für euch wahrscheinlich einen schönen Tag 😉

Liebe Grüße,
Julian


214x gelesen

Print Friendly, PDF & Email

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.