Warum funktioniert meine simple App nicht? (Android Studio)

  • Antworten:17
Arne
  • Forum-Beiträge: 41

24.09.2016, 19:48:19 via Website

Hi Leute,

Bin neu auf diesem Gebiet und habe gerade meine erste App geschrieben, welche nicht funktioniert.

Anbei der Code (bitte die ganzen überflüssigen Imports ignorieren).

Das Layout habe ich nicht geändert, also sollte eigentlich die "Hello world" - Anzeige erscheinen, während das Programm abläuft.

Auf jeden Fall bekomme ich die Meldung "Filetclient reagiert nicht", wenn ich die App auf mein phone draufspiele. Gradle gibt 0 Fehler und 0 Warnungen raus. Auf dem Server kommt auch kein Verbindungsaufbau an. Mein Phone ist mit dem Server 100%ig verbunden. Das kann ich einfach mit anderen Apps testen.

Hat jemand eine Ahnung, woran das liegen könnte? Danke!


package com.example.blabla.filetclient;

import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io_OutputStream;
import java.net.Socket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Socket socket;

    @override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // android.os.Debug.waitForDebugger();


        try {
            this.socket = new Socket("192.168.178.32", 80);
        } catch (IOException e) {
            e.printStackTrace();
        }

        File file = new File(Environment.getExternalStorageDirectory(), "picture.jpg");

        byte[] bytes = new byte[(int) file.length()];
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

            bis.read(bytes, 0, bytes.length);

            bos.write(bytes, 0, bytes.length);
            bos.flush();
            socket.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

— geändert am 24.09.2016, 22:33:06 durch Moderator

Antworten
swa00
  • Forum-Beiträge: 3.704

24.09.2016, 20:35:42 via Website

Hallo Arne ,

willkommen im Forum.

Nun , da sind einige Dinge falsch - ich beschränke mich auf das Wesentliche

a) in deinem Errorlog kannst du bestimmt auch sehen , warum das nicht geht
b) Hast du denn die Manifest angepasst ?
c) ein Zugriff über das netz realisert man in einem (Async)Thread.
d) so etwas soll man auch nicht in "onCreate" tun - die ist hauptsächlich dafür da , die Activity zu initialisieren.

Schau dir mal dazu diverse Beispiele und Tutorials im Netz an

lg
Stefan

— geändert am 24.09.2016, 20:37:18

Liebe Grüße - Stefan
[ App - Entwicklung ]

ArneLudy

Antworten
Arne
  • Forum-Beiträge: 41

24.09.2016, 22:45:11 via Website

Danke Stefan!

Hier die letzten Zeilen vom Logcat log (die Zeilen davor sind zu viele, dort finde ich hauptsächlich "could not find method..." und "could not find class..." -Meldungen, die wahrscheinlich nicht ausschlaggebend sind, da ich sonst beim Compilieren Probleme bekommen würde).

image

Die Manifestdatei habe ich nur insofern angepasst, dass ich die Permissions für INTERNET und READ_EXTERNAL_STORAGE hinzugefügt habe.

Dass man sowas eher nicht in der onCreate der Hauptklasse unternimmt, habe ich mir schon gedacht. Andererseits habe ich Apps gesehen, bei denen man das gemacht hat. Zumindest das mit den Sockets, meine ich zumindest. Nun bin ich etwas irritiert... was darf man alles in die onCreate packen und was nicht? Als C-Programmierer bin ich es eher gewohnt alles in die Hauptfunktion zu packen, gerade bei kleinen Programmen.

— geändert am 24.09.2016, 22:47:10

Antworten
Ludy
  • Admin
  • Forum-Beiträge: 7.957

24.09.2016, 22:49:05 via Website

Hallo Arne,

ich habe deinen Code konvertiert, so ist er besser zu lesen.

Ich kann Stefan nur zustimmen, du wirst mit Sicherheit ein NetworkOnMainThreadException bekommen.

Man sollte nicht sondern man darf laut der Android Konventionen, keine Netzwerk bezogene Funktionen/Methoden/Threads ausführen.

Da du in der StorageDirectory schreiben/lesen möchtest, muss dafür die Berechtigung eingestellt sein.

Dein socket#close wird nur geschlossen, wenn kein Error ausgelöst wird, ist etwas unsauber nutze try-catch-finally .
Genauso deine BufferedOutputStream und BufferedInputStream werden nicht geschloßen, auch unsauber.


So in etwa sollte es aussehen

new AsyncTask<String, String, String>() {

    @Override
    protected String doInBackground(String... params) {
        try {
            this.socket = new Socket("192.168.178.32", 80);
        } catch (IOException e) {
            e.printStackTrace();
        }

        File file = new File(Environment.getExternalStorageDirectory(), "picture.jpg");

        byte[] bytes = new byte[(int) file.length()];
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

            bis.read(bytes, 0, bytes.length);

            bos.write(bytes, 0, bytes.length);
            bos.flush();
            socket.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
// hier schließt du alles ;-)
        }
        return null;
    }
}.execute();

— geändert am 24.09.2016, 22:57:10

Gruß Ludy (App Entwickler)

Mein Beitrag hat dir geholfen? Lass doch ein "Danke" da.☺

☕ Buy Me A Coffee ☕

Lebensmittelwarnung-App

✨Meine Wunschliste✨

📲Telegram NextPit News📲

Arneswa00

Antworten
swa00
  • Forum-Beiträge: 3.704

24.09.2016, 23:38:53 via Website

Hallo Arne,

vorweg : Ludy hat die wesentliche Punkte erklärt, weshalb ich nicht auf diese erneut eingehen muss.
Dein Errorlog muss dir im übrigen noch angezeigt haben , das ein "StrictMode" fehler vorliegt , der wird dir
ausgegeben , wenn du einen Netzwerkzugriff ohne Thread laufen lässt.

Vielleicht noch ein paar hilfreiche Dinge , da ich selbst beruflich C/C++/MFC-geschädigt bin und das schon über 20 Jahre tue :-) Android erst seit ca. 2 Jahren , aber ich habe eine Menge Berge erklimmen müssen.

a) Denke um - (oder dazu) -AndroidJava ist komplett anders und du wirst dein blaues Wunder erleben - leider
b) Unsere in C-geliebten statischen/globalen Variablen gibt es nicht - lese bitte dazu mal "SIngleton" durch
c) Du musst unbedingt verstehen , was Android mit deinem Code macht - Android haut dir alles das raus , was es nicht braucht (Stichwort GC & Lifecycle) und du wunderst dich , das dir teilweise als sichere geltende Routinen plötzlich Werte fehlen oder ganze Klassen weg sind . - UND DAS ZUR LAUFZEIT deiner App (im C-Sinne).
d) Verstehe ,was passiert ,wenn die App in den Hintergrund wandert und was dann android damit macht
e) Windowhandle im üblichen Sinne gibt es nicht, Variablen einfach durch die Gegend schieben auch nicht .
f) Threads sind nicht Threads - da gibt es mehrere Techniken , einige kannst du nur für ein paar Sekunden einsetzen , andere wiederum lange - auch da muss man sich entscheiden , welche man nimmt.
Dazu auch : je nach verwendeter Technik kannst du NICHT einfach ein paar threads starten - negativ , die werden HINTEREINANDER ausgeführt und warten gegenseitig auf sich (auch wenn da ASYNC steht - das hat mit dem C-ASYNC mal gar nichts zu tun :-)
g) Abgekapselte Bibliotheken ( DLL/LIB) gibt es nicht mehr, sie werden zu einem Gesamt-teil deiner Projekte.
(Also keine lib Einsprungadressen mehr)
h) Achte bei der Suche eines Problems immer auf das Datum der Lösung und darüber hinaus , was du für eine
SDK version benutzt. Android lebt , demensprechend jede Mende geändert und deprecated usw.
i) new ist nicht gleich dem c new - malloc. usw gibt es nicht- und auch das entsprechende free nicht - java new ist NICHT statisch - im C-Sinne

Zum malloc mal als Erklärung : ein malloc-ähnliches vergleiche ich bei Java/Android in etwa so :
"Du willst ein malloc ? ok, ich überlege es mir mal , ob du es bekommst und ich entscheide dann , wie lange du denn darauf zugreiffen darfst- wenns nicht mehr da ist , sage ich dir auch nicht bescheid - ICH, liebes System habe entschieden, dass das nicht mehr benötigt wird- sehe ich für Sinnlos an , denn du hast eine gewisse Zeit nicht mehr drauf zugegriffen" :-)
.
.
Ich würde fast behaupten : Wenn es ans Eingemachte geht : Ausser dem Syntax hat Java/ANdroid gar nichts
mit C zu tun . Vieles ist nicht Eindeutig, eher schwammig .
Und bei so manchen Sachen sollten die "Erfinder" verprügelt werden :-)
.

Andererseits habe ich Apps gesehen, bei denen man das gemacht hat. Zumindest das mit den Sockets, meine ich zumindest

Yupp, vieles ist Schrott - und als Newbie frustet es , wenn du Schrott kopiert hat :-)

Und wenn du Fragen hierzu hast - bist du natürlich gerne willkommen

lg
Stefan

— geändert am 25.09.2016, 00:25:35

Liebe Grüße - Stefan
[ App - Entwicklung ]

ArneLudy

Antworten
Arne
  • Forum-Beiträge: 41

25.09.2016, 03:29:21 via Website

Danke Ihr beiden! Ich werde den Code gleich ausprobieren... und mich zurückmelden.

Ja, in der Tat habe ich einen StrictMode-Fehler! (sieht man übrigens auch in dem Screenshot, den ich hochgeladen hatte, weil ich die Ausgabe hier nicht posten konnte bzw. durfte. Sichtbar?)

Und danke für die vielen Umsteiger-Tipps, Stefan! Ein paar Sachen waren mir schon bewusst. Ein ganz blutiger Anfänger bin ich nämlich nicht. Zumindest die Syntax verstehe ich ziemlich gut; war auch einer der wenigen die in der Klausur eine 1 geschrieben haben. Aber praktische Erfahrungen habe ich praktisch Null. Das hier kann man wohl als mein allererstes Programm bezeichnen.
Das mit den Threads fand ich interessant. Wofür MUSS man eigentlich genau Threads verwenden, außer für Sockets? Ehrlich gesagt bin ich in C auch immer ohne ausgekommen. Und dass Lösungen abhängig von der SDK-Version sind, habe ich auch schon erfahren können. Der Preis war viel, kurzfristige Verwirrung.

Okay ich probiere den Code aus und melde mich... Übrigens, wenn das ganze klappt, möchte bzw. muss ich aus dem ganzen einen Code für den MIT AppInventor machen. Hat einer von euch zufällig Erfahrungen damit?

LG!

— geändert am 30.09.2016, 21:45:16

Antworten
swa00
  • Forum-Beiträge: 3.704

25.09.2016, 08:56:46 via Website

Guten Morgen Arne,

Wofür MUSS man eigentlich genau Threads verwenden

Ganz schlicht , um die "Freiläufigkeit" des Systems zu garantieren.
Es gibt natürlich noch detaillierte und tiefere Gründe.
http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html

möchte bzw. muss ich aus dem ganzen eine Extension für den MIT AppInventor machen. Hat einer von euch zufällig Erfahrungen damit?

Was dich auch dazu geritten hat, von meiner Seite muss ich die Frage leider vereinen :-)

lg
Stefan

— geändert am 25.09.2016, 10:23:03

Liebe Grüße - Stefan
[ App - Entwicklung ]

Arne

Antworten
Arne
  • Forum-Beiträge: 41

25.09.2016, 18:17:02 via Website

Hey danke. Also ich weiß wozu Threads generell gut sind, Multitasking u.s.w., nur würde ich gerne wissen, wo es in Java verpflichtend ist, Threads zu verwenden. Ich werde mich bei Gelegenheit mal in den Artikel einlesen.

Im Moment versuche noch, den Code von Ludy zu implementieren. Leider mache ich das wohl aber falsch. Mein Problem ist, dass ich weiß, wie ich das genau mache, weil ich die Sytax hinsichtlich des Coderahmens nicht verstehe.

new AsyncTask() {

...

}.execute();

Es ist sieht einerseits aus wie eine Initialisierung (wegen dem new) andererseits wie auch wie ein Methodenaufruf (.execute()).
Wie und an welcher Stelle bringe ich das genau ein? Innerhalb oder außerhalb von OnCreate? Bzw., muss ich das nicht als Oberklasse von MainActivity gestalten? also

public class MainActivity extends AsyncTask() {

...

So in der Art? Ich meine zumindest das mal so gesehen zu haben.

Vielleicht wäre es gut, wenn Ihr mir vielleicht noch schreiben könntet, was genau ich vor und nach dem Codeabschnitt hinzufügen muss.

Danke für alles.

LG

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

25.09.2016, 18:50:12 via Website

Beides ist richtig:
mit new wird der AsyncTask initialisiert, und anstatt erst eine Variable zu machen und dann execute aufzurufen wird hier das Execute halt direkt aufgerufen, kann man machen, wenn man das AsyncTask Objekt nicht woanders braucht etc..

Das zweite mit extends ist die Vererbung, dann erbt deine Activity von AsyncTask, das ist nicht üblich dann macht man lieber eine eigene Klassendatei dafür.
Das Beispiel von Ludy ist zum einmaligen ausführen, da wird mit anoymen klassen gearbeitet...

Ud wo das hinkommt, da wo die Verbindung aufgebaut werden soll.

Ich würde das nicht in der onCreate machen, denn ich habe immer gere eine App die ohne Aktion startet und einen Button.
Wenn ich den dann klicke wird etwas ausgeführt, wie z.b. die TCP Verbindung.

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

Arneswa00Ludy

Antworten
Arne
  • Forum-Beiträge: 41

25.09.2016, 22:47:01 via Website

Danke Pascal!

Also, ich habe mich dann mal für Weg 2 entschieden. Sprich, extra Klasse für den Verbindungskram. Die Codes sehen nun so aus:

Hauptcode:

package com.example.blabla.filetclient2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.io.File;

public class MainActivity extends AppCompatActivity {

File file;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new TCPClient().execute();
}

}

Verbindungs-Code:

package com.example.blabla.filetclient2;

import android.os.AsyncTask;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;

public class TCPClient extends AsyncTask {

Socket socket;

public TCPClient (){
}

@Override
protected void doInBackground() {
try {
this.socket = new Socket("192.168.178.32", 80);
} catch (IOException e) {
e.printStackTrace();
}

    File file = new File(Environment.getExternalStorageDirectory(), "picture.jpg");

    byte[] bytes = new byte[(int) file.length()];
    try {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        BufferedOutputStream bos = new BufferedOutputStream(this.socket.getOutputStream());

        bis.read(bytes, 0, bytes.length);

        bos.write(bytes, 0, bytes.length);
        bos.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        socket.close();

// bis.close();
// bos.close();
}
}
}

Fragen:

1.) Leider kann ich die Streams nicht schließen ("Cannot resolve Symbol bis") (deshalb oben ausgeklammert). Warum?

2.) Beim Compilieren bekomme ich nun folgende Meldung:

Error:(16, 8) error: TCPClient is not abstract and does not override abstract method doInBackground(Void...) in AsyncTask

Er deutet auf die erste Zeile, wo die Klasse TCPClient definiert wird. Was habe ich falsch gemacht?

Danke für die Hilfe

Antworten
Arne
  • Forum-Beiträge: 41

25.09.2016, 23:03:38 via Website

Achja, noch eine Frage:

Ich habe gelesen, dass AsyncTask nur für kurze Prozesse von max. ein paar Sekunden geeignet sein soll. Ich möchte ja eine ganze Datei verschicken. Das kann schon mehrere Minuten dauern, je nach Verbindung. Wird das ein Problem werden?

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

26.09.2016, 14:09:57 via App

Selbst lange AsyncTasks sollten bei richtiger benutzung nicht zum Problem werden. Habe da keine Bedenken.

Zu oben:

  1. Du kannst die Streams nicht schließen, da sie inerhalb des try definiert. Somit sind diese auch nur da gültig. Die Definition muss vorher passieren und die Intitialisierung dann innerhalb vom try. dann kannst du im finally die dinger auch zumachen.

  2. Ein AsyncTask ist ein etwas komplexeres Konstrukt, da es eine Multigenerische Klasse ist. Um davon zu rben musst du z.b. den task mit AsyncTask definieren, wenn der AsyncTask keine Werte zurückgibt. Ansonsten gibt man in den Spitzen Klammern die Return Datentypen an.

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

Arneswa00

Antworten
swa00
  • Forum-Beiträge: 3.704

26.09.2016, 14:22:43 via Website

Selbst lange AsyncTasks sollten bei richtiger benutzung nicht zum Problem werden. Habe da keine Bedenken.

Pascal - jetzt scheiden sich die Geister :-)

Du schreibst das Gleiche , ich hatte auch noch nie Probleme mit "längeren" AsyncTasks aber irgendwas müssen
die Jungs im Hintergrund machen , von dem wir alle nichts wissen :-)
.
.
https://developer.android.com/reference/android/os/AsyncTask.html

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)

Source :
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/AsyncTask.java
.
Kein Wort darüber, warum, weshalb und welcher Umstand - iss halt so ....

.
Und nu ? :-)

.

@Arne : genau so etwas meinte ich oben mit "schwammig" :-)
Man ist sich nicht mehr sicher, ob seine App in der freien Wildnis irgendwann mal das Zeitliche segnet
und man weis nicht warum ....... ziemlich ungutes Gefühl.

.

lg
Stefan

— geändert am 26.09.2016, 14:53:50

Liebe Grüße - Stefan
[ App - Entwicklung ]

Arne

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

26.09.2016, 14:47:34 via App

Wenn man mal nachschaut versteht man auch warum:
http://stackoverflow.com/a/13082084

Das ganze scheint ein Ressourcen Problem zu sein, da man den AsyncTask auch am Ende zum updaten der Views nutzen kann, hält der gc die Activity aktiv. Somit kann daraus ein Mem Leak werden.

Dann würde ich doch auf den Normalen Thread zurückgreifen. Oder je nach dem wie die Tcp laufen muss einen Service dafür erstellen.

PS: Wie gesagt kann aber nuss nicht. Leider habe ich keine MaxTime beschränkung gefunden... Aber liegt immer am Programmierer, wenn man keine View reference im Task hat, dürfte es zu wenig Problemen kommen. Sicher ist das aber nie...

— geändert am 26.09.2016, 14:49:06

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

Arne

Antworten
swa00
  • Forum-Beiträge: 3.704

26.09.2016, 14:51:34 via Website

Wenn man mal nachschaut versteht man auch warum:
http://stackoverflow.com/a/13082084
Das ganze scheint ein Ressourcen Problem zu sein, da man den AsyncTask auch am Ende zum updaten der Views nutzen kann, hält der gc die Activity aktiv. Somit kann daraus ein Mem Leak werden.

Den Artikel hatte ich dann auch gefunden - allerdings bei stackoverflow .
Schöner wäre halt eine Aussage auf der "developer" seite gewesen und nicht von "sinicolas" aus 2012 ....

Liebe Grüße - Stefan
[ App - Entwicklung ]

Arne

Antworten
Arne
  • Forum-Beiträge: 41

26.09.2016, 23:56:11 via Website

Hey Ihr beiden,

danke für Eure Recherchen, auch wenn ich für mich daraus noch keine Schlüsse ziehen kann.

Nach etwas Bastelei habe ich nun endlich meine App zum laufen bekommen. Und sie läuft perfekt! Und mit AsyncTask. 1,6 MB große Datei wurde über 5 Minuten ohne Zwischenfälle übertragen. Die lange Dauer muss am Server liegen... daran werde ich noch arbeiten müssen.

Aber vielen Dank an Euch... Bestimmt lest Ihr in ein paar Tagen wieder von mir... ich beschäftige mich momentan viel mit App-Programmierung und irgendwie lässt mich das Gefühl nicht los, dass das nächste Problem schon auf mich wartet ;-)

Meinen letzten Code habe ich hauptsächlich in 2 Zeilen geändert:

...
public class TCPClient extends AsyncTask {
...
protected Void doInBackground(Void... voids) {
...

Schon sehr mysteriös, dieses Java...

swa00

Antworten
swa00
  • Forum-Beiträge: 3.704

27.09.2016, 00:08:01 via Website

Hallo Arne,

herzlichen Glückwunsch an dieser Stelle !!!

Und natürlich bist du gerne herzlichst willkommen , auch wenn es nur Probleme gibt :-)

lg
Stefan

— geändert am 27.09.2016, 00:13:05

Liebe Grüße - Stefan
[ App - Entwicklung ]

ArnePascal P.

Antworten
Arne
  • Forum-Beiträge: 41

29.09.2016, 22:15:59 via Website

Danke!

Ich habe gerade erfahren, dass ich für mein Vorhaben (App Inventor Extension) mit "richtigen" Threads arbeiten muss. Also mit AsynchUtil und Runnable() u.s.w. Kann einer von euch vielleicht auf Anhieb sagen, wie ich den obigen Code hierfür umgestalten müsste?

Antworten