Verbindung zur API herstellen

  • Antworten:14
  • Bentwortet
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 12:41:18 via Website

Hey,

also ich bin momentan daran just for fun ne App zu entwickeln... bin auch schon recht weit, allerdings waren die Daten bis dato "hardgecodet".... nun möchte ich einen Schritt weiter gehen und meine Daten von meiner Api holen! Wenn ich diese im "Advanced Rest Client" von Chrome teste funktioniert auch alles.
Wie auch immer ich habe mich jetzt um nur mal sicher zu gehen dazu entschieden zunächst einmal mit einer sicher funktionieren Api zu testen, um das Empfangen von Daten hin zu bekommen leider klappt es nicht:(

Hier erstmal mein Code:

public String getData() {
    String jsonResult = null;
    HttpClient httpclient = new DefaultHttpClient();
    Log.i("Stub","Zeile 1");
    HttpGet httpget = new HttpGet(url);
    Log.i("Stub","Zeile 2");
    try {
        HttpResponse response = httpclient.execute(httpget);
        Log.i("Stub","Zeile 3");
        jsonResult = inputStreamToString(response.getEntity().getContent())
                .toString();
    }

    catch (ClientProtocolException e) {
        Log.i("Stub","Exception"+e.getMessage());
        e.printStackTrace();
    } catch (IOException e) {
        Log.i("Stub","Exception"+e.getMessage());
        e.printStackTrace();
    }
    Log.i("Stub","Zeile 4");
    return jsonResult;
}

Gebe ich die url in den Advanced Rest Client ein bekomme ich wie gewünscht das json!
Er gibt mir im Log-Cat ne FATAL EXCEPTION und killt die app! Dies passiert nach Log.i Zeile 2! Eine Exception-Message wird nicht ausgegeben...

Sieht jemand den Fehler?

— geändert am 11.09.2014, 12:47:45

Antworten
Fabian Simon
  • Forum-Beiträge: 359

11.09.2014, 13:10:28 via Website

Hast an die Berechtigung gedacht ?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

11.09.2014, 13:15:24 via Website

Hallo Sven,

Wilkommen im Forum! :)

Mit welcher IDE arbeitest du denn?
Normalerweise hat man immer einen Log, der auch die Exception anzeigt, dieser heißt LogCat.
Darib befinden sich alle Degubrelevanten daten.
Wenn du den Log hast, wäre es hilfreich den rot Markierten Teil zu Posten, da dies der Fehler ist.

Ich schätze aber, dass es eine NetworkOnMain Exception ist.
Dies bedeutet, dass Netzerkoperationen/Laden von Daten aus dem Internet nicht im Normalen UI Thread gemacht werden können.
Also musst du deinen Code in einen Thread oder async Task aulagern.
Ein Tutorial dafür haben wir hier: https://www.nextpit.de/forum/568854/tutorial-download-einer-webseite.

PS: Hast du an die Manifest Permission edacht, die du zum zugriff ins Internet benötigst?

LG Pascal

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 13:40:01 via Website

Hey,

danke für die schnellen Antworten!

Ich glaube ich habe nicht an die Berechtigung gedacht:)
Ich glaube ich werde nachher mal das Tutorial sowie die Berechtigungen angucken und mich im Anschluss noch einmal melden!

Gruß
Sven

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 14:11:26 via Website

Hi Fabian,

ich habe das mit der Berechtigung mal gecheckt, also ich hatte die hier schon angegeben:

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

Brauche ich noch weitere? Weil das war die einzige die in einem anderen Tutorial (welches ich als Grundlage genommen hatte) angegeben war!

Gruß
Sven

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

11.09.2014, 14:18:54 via Website

Nein, das ist die einzige die du benötigst.

LG Pascal

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 14:32:21 via Website

Hi Pascal,

also ich muss zugeben ich habe das Tutorial eben nur überflogen, aber soweit ich das verstehe "muss" ich das ganze in einen eigenen Thread stecken, bzw. es ist besser damit das laden der Daten parallel zur Nutzerinteraktion stattfinden kann..., dazu erbe ich einfach vom AsyncTask und überschreibe dessen Funktion doInBackground()... Dies habe ich mal schnell implementiert doch leider ist bleibt der selbe Fehler:

public class TestStub extends AsyncTask<String, Void, String>{

@Override
protected String doInBackground(String... param) {
    String jsonResult = null;
    HttpClient httpclient = new DefaultHttpClient();
    Log.i("Stub","Zeile 1");
    HttpGet httpget = new HttpGet(url);
    Log.i("Stub","Zeile 2");
    try {
        HttpResponse response = httpclient.execute(httpget);
        Log.i("Stub","Zeile 3");
        jsonResult = inputStreamToString(response.getEntity().getContent())
                .toString();
    }

    catch (ClientProtocolException e) {
        Log.i("Stub","Exception"+e.getMessage());
        e.printStackTrace();
    } catch (IOException e) {
        Log.i("Stub","Exception"+e.getMessage());
        e.printStackTrace();
    }
    Log.i("Stub","Zeile 4");
    return jsonResult;
}

private StringBuilder inputStreamToString(InputStream is) {
           String rLine = "";
           StringBuilder answer = new StringBuilder();
           BufferedReader rd = new BufferedReader(new InputStreamReader(is));

       try {
        while ((rLine = rd.readLine()) != null) {
         answer.append(rLine);
        }
       }catch (IOException e) {
            e.printStackTrace();
           }
    return answer;
   }

}

Kurz zu deinen Fragen ich benutze Eclipse, also die Eclipse Version die man bei android com saugen kann und die neuste...
Das LogCat sagt: FATAL EXCEPTION: main

Gruß
Sven

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

11.09.2014, 14:38:37 via Website

In LogCat müsste eigenlich mehr stehen?
Stürtzt die App gleich beim starten ab oder erst wenn der Download anfängt?

PS: Wie startest du den Task?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 14:40:37 via Website

Ach voll verpeilt hier die Fehler:

09-11 08:16:49.995: W/dalvikvm(1949): threadid=1: thread exiting with uncaught exception (group=0xb2cfbb20)
09-11 08:16:50.015: E/AndroidRuntime(1949): FATAL EXCEPTION: main
09-11 08:16:50.015: E/AndroidRuntime(1949): Process: com.example.parsejson, PID: 1949
09-11 08:16:50.015: E/AndroidRuntime(1949): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.parsejson/com.example.activitys.MainActivity}: android.os.NetworkOnMainThreadException
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.ActivityThread.access$800(ActivityThread.java:135)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.os.Handler.dispatchMessage(Handler.java:102)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.os.Looper.loop(Looper.java:136)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.ActivityThread.main(ActivityThread.java:5017)
09-11 08:16:50.015: E/AndroidRuntime(1949): at java.lang.reflect.Method.invokeNative(Native Method)
09-11 08:16:50.015: E/AndroidRuntime(1949): at java.lang.reflect.Method.invoke(Method.java:515)
09-11 08:16:50.015: E/AndroidRuntime(1949): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
09-11 08:16:50.015: E/AndroidRuntime(1949): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
09-11 08:16:50.015: E/AndroidRuntime(1949): at dalvik.system.NativeStart.main(Native Method)
09-11 08:16:50.015: E/AndroidRuntime(1949): Caused by: android.os.NetworkOnMainThreadException
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1145)
09-11 08:16:50.015: E/AndroidRuntime(1949): at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
09-11 08:16:50.015: E/AndroidRuntime(1949): at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
09-11 08:16:50.015: E/AndroidRuntime(1949): at java.net.InetAddress.getAllByName(InetAddress.java:214)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:137)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
09-11 08:16:50.015: E/AndroidRuntime(1949): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
09-11 08:16:50.015: E/AndroidRuntime(1949): at com.example.controller.TestStub.doInBackground(TestStub.java:29)
09-11 08:16:50.015: E/AndroidRuntime(1949): at com.example.controller.ServiceDelegate.getData(ServiceDelegate.java:22)
09-11 08:16:50.015: E/AndroidRuntime(1949): at com.example.activitys.MainActivity.onCreate(MainActivity.java:50)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.Activity.performCreate(Activity.java:5231)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
09-11 08:16:50.015: E/AndroidRuntime(1949): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
09-11 08:16:50.015: E/AndroidRuntime(1949): ... 11 more

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 14:44:06 via Website

Und so starte ich das ganzen:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String s = sd.getData();
    TextView t = (TextView) findViewById(R.id.texttest);
    t.setText(""+s);

Das geht dann weiter an eine klasse die aufgaben verteilt

    public String getData(){
    String s = tstub.doInBackground(url);
    return s;
}

die dann direkt die doInBackground Funktion aufruft

und wie gesagt im Log wird noch der Log Zeile 2 ausgegeben also geht was beim Verbindungsaufbau schief würde ich behaupten!

in der Zeile:

HttpResponse response = httpclient.execute(httpget);

— geändert am 11.09.2014, 14:48:42

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

11.09.2014, 14:48:03 via Website

Ist ja wieder der gleiche Fehler wie vorher, du musst ja sagen dass der Task starten soll, mit DeinTask#execute(Parameter..)
Sonst ist das ja einfach so als hättest du deinen Ladecode einfach in eine Methode ausgelagert, die DoInBackgroun eisst.
Also fettgedruckte Zeile am anfang des Tuts nicht beachtet.. :)

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 15:37:31 via Website

Hey,

schon mal danke bin dadurch weiter^^

Wenn ich die Klasse so aufrufe:

new TestStub().execute(url);

geht es und im Log wird das Json als String wie geplant ausgegeben! Jetzt habe ich aber noch ein Problem und ein weiterführende Frage:

Problem:
Wie komme ich an diesen String ran? Also zum parsen in meine Models... Das geht ja nicht... :

String s = new TestStub().execute(url);

Frage:
Diese AsyncTask-Klasse hält ja noch andere Methoden bereit wie bspw. onProgressUpdate(), so nun kann ich wahrscheinlich im Selben Task nur immer eine dieser Methoden benutzen oder?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

11.09.2014, 15:48:34 via Website

Nein,
für nähere Infos zum AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html

Es gibt nun 2 Möglichkeiten an den string zu kommen:

  1. String s = new TestStub().execute(url).get();
    Da wird aber wieder der UI Thread lahmgelegt, d.h. die App reagiert solage (während des ladens) nicht auf die eingebe des Users, dies kann unter Umständen auch malö zu einem Absturz führen.

  2. Du implementierst einen Callback und dieser "Meldet" sich wenn das laden Fertig ist, dann kann der String weiterverarbeitet werden.
    Wenn du mich fragst ist das die beste und "sauberste" Methode Daten asynchron zu laden.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Sven Bone
  • Forum-Beiträge: 8

11.09.2014, 16:02:35 via Website

Also wenn ich das richtig verstehe ist das Async praktisch fürn arsch wenn ich .get() verwende, weil er dadurch eh auf eine Antwort wartet richtig?

Dann werde ich mir am Wochenende auf jeden Fall das mit dem Callback anschauen, ich stehe nämlich schon auf eine zumindest im Ansatz saubere Architektur, erst garnicht mit dem "cheaten" anfangen ;)

Kannst du mir zufällig ein gutes Tutorial oder gute Examples empfehlen?

Und vielen Dank für die Hilfe!:D

Antworten