1. Nimm jetzt an unserem 2. ADVENT-Gewinnspiel teil - Alle Informationen findest Du hier!

Packageübergreifende Variable: "Die Anwendung ... wurde unerwartet beendet"

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von Andro-medanebel, 09.02.2011.

  1. Andro-medanebel, 09.02.2011 #1
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Mein Programm soll solange warten, bis onSizeChanged ausgeführt wurde,
    da dort Breite und Höhe meines Layouts ermittelt werden, die ich für
    die weitere Programmausführung brauche.

    Dafür wollte ich eine Hilfsvariable nutzen, die mit 0 initialisiert wird
    und auf 1 gesetzt wird, wenn onSizeChanged() ausgeführt wurde.

    Für diese Hilfsvariable habe ich ein Package mit einer Klasse,
    die eine get- und eine set-Methode enthält, geschaffen.

    Wenn ich jedoch ein Zugriff auf die Methoden erfolgt, bekomme
    ich einen "Die Anwendung ... wurde unerwartet beendet"-Fehler.

    Meine Programmstruktur:
    Code:
    com
     customview
       CustomLayout.java
     memory
       MemoryActivity.java
    variablen_fuer_mehrere_klassen
       VariablenFuerActivityUndView.java
    
    In CustomLayout.java und MemoryActivity.java importiere ich die Hilfsklasse:
    Code:
    import variablen_fuer_mehrere_klassen.VariablenFuerActivityUndView;
    
    Meine Hilfsklasse im Package variablen_fuer_mehrere_klassen;:
    Code:
    package variablen_fuer_mehrere_klassen;
    
    public class VariablenFuerActivityUndView {
     public static int hilfsvar = 0;
     public int getHilfsvar() {
        return hilfsvar;}
     public void setHilfsvar(int i) {
            hilfsvar = i;}
    }
    
    
    In CustomLayout.java versuche ich nun in der Methode onSizeChanged,
    die Methode setHilfsvar aufzurufen, was jedoch zu dem Laufzeitfehler
    "Die Anwendung ... wurde unerwartet beendet" führt.

    Code:
    ...
    import variablen_fuer_mehrere_klassen.VariablenFuerActivityUndView;
    public class CustomLayout extends RelativeLayout{
        VariablenFuerActivityUndView h;
          protected void onSizeChanged(int w, int h, int ow, int oh)
          {
           ...
           setzeHilfsvarAufEins(); //direkter Aufruf von h.setHilfsvar(1); führt hier
                                   //zu "Cannot invoke setHilfsvar(int) on the primitive type int"-Fehler
                                   //deshalb Aufruf in Methode verschoben
          }
          
          public void setzeHilfsvarAufEins()
          {
           h.setHilfsvar(1); //Führt zu "Die Anwendung ... wurde unerwartet beendet"-Fehler
          }
    ...
    
    Logcat-Error-Ausgabe:
    Code:
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764): FATAL EXCEPTION: main
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764): java.lang.NullPointerException
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at com.customview.CustomLayout.setzeHilfsvarAufEins(CustomLayout.java:54)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at com.customview.CustomLayout.onSizeChanged(CustomLayout.java:48)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.View.setFrame(View.java:7101)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.View.layout(View.java:7028)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.View.layout(View.java:7034)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.View.layout(View.java:7034)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.View.layout(View.java:7034)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.ViewRoot.performTraversals(ViewRoot.java:1049)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1744)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.os.Handler.dispatchMessage(Handler.java:99)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.os.Looper.loop(Looper.java:144)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at android.app.ActivityThread.main(ActivityThread.java:4937)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at java.lang.reflect.Method.invokeNative(Native Method)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at java.lang.reflect.Method.invoke(Method.java:521)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    02-09 17:15:39.056: ERROR/AndroidRuntime(4764):     at dalvik.system.NativeStart.main(Native Method)
    02-09 17:16:00.056: ERROR/ClockWidget(250): weatherClock onReceive~ mUseAnimation:false
    02-09 17:16:00.056: ERROR/ClockWidget(250): weatherClock onReceive~ mUseAnimation:false
    
    
    Weshalb bekomme ich den Laufzeitfehler und was muss ich ändern,
    um auf meine get- und set-Methoden in der Hilfsklasse zugreifen
    zu können?
     
  2. Kranki, 09.02.2011 #2
    Kranki

    Kranki Ehrenmitglied

    Beiträge:
    3,831
    Erhaltene Danke:
    814
    Registriert seit:
    19.07.2009
    Tablet:
    Samsung Galaxy Tab 3 7.0 Lite
    Wird h auch irgendwo initialisiert?
     
    Andro-medanebel bedankt sich.
  3. Andro-medanebel, 09.02.2011 #3
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Habe folgende Änderungen vorgenommen:

    Code:
    ...
    import variablen_fuer_mehrere_klassen.VariablenFuerActivityUndView;
    public class MemoryActivity extends Activity {
        VariablenFuerActivityUndView h = new VariablenFuerActivityUndView();
        //vorher: VariablenFuerActivityUndView h;
       ...
       do {} while (h.getHilfsvar()==0);
    ...
    import variablen_fuer_mehrere_klassen.VariablenFuerActivityUndView;
    public class CustomLayout extends RelativeLayout{
        VariablenFuerActivityUndView h = new VariablenFuerActivityUndView();
        //vorher: VariablenFuerActivityUndView h;
    
    
    Kann man das
    Code:
    VariablenFuerActivityUndView h = new VariablenFuerActivityUndView();
    als initialisieren bezeichnen?
    Dann habe ich das hiermit getan.

    Nun bekomme ich keinen Laufzeitfehler mehr.
    Allerdings lande ich mit
    Code:
    public class CustomLayout extends RelativeLayout{
        VariablenFuerActivityUndView h = new VariablenFuerActivityUndView();
        ...
        do {} while (h.getHilfsvar()==0);
        ...
    
    in einer Endlosschleife.

    Die Schleife sollte aber nur solange durchlaufen werden, bis
    die Methode onSizeChanged hilfsvar auf 1 setzt.

    Habe ich mir jetzt zwei unabhängige Klassenvariablen geschaffen?
    Wie kann ich eine schaffen, deren Attributänderung (hilfsvar)
    sich sowohl in der Klasse CustomLayout als auch in der Klasse
    MemoryActivity auswirkt?
     
  4. Zoopa, 09.02.2011 #4
    Zoopa

    Zoopa Android-Experte

    Beiträge:
    599
    Erhaltene Danke:
    173
    Registriert seit:
    28.07.2010
    Da deine Variable static ist, gibts nur eine davon, das ist schon richtig so.
    Dein Problem ist, dass du zeitintensive Dinge (hier deine Schleife) in einen eigenen Thread packen musst, sonst blockiert dir der GUI-Thread.
     
    Andro-medanebel bedankt sich.
  5. Andro-medanebel, 09.02.2011 #5
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Aber meinen Thread zu blockieren ist ja gerade das, was ich will.
    Die do-while-Schleife soll solange warten, bis onSizeChanged
    aufgerufen wurde, weil vorher Breite und Höhe meines Layouts
    nicht bekannt sind, ich aber abhängig von Breite und Höhe
    unterschiedlich viele Buttons erzeugen will.
     
  6. Kranki, 09.02.2011 #6
    Kranki

    Kranki Ehrenmitglied

    Beiträge:
    3,831
    Erhaltene Danke:
    814
    Registriert seit:
    19.07.2009
    Tablet:
    Samsung Galaxy Tab 3 7.0 Lite
    Pack dir erstmal Debug-Ausgaben (Log.d()) in den Setter deiner Hilfsklasse, in onSizeChanged und vor und nach der Schleife.
    Außerdem wäre es evtl. gut, die Schleife auszukommentieren und jeweils mit Thread.currentThread() zu gucken, ob die beiden Methoden nicht zufällig im selben Thread laufen, sonst kann die Schleife da warten bis sie schwarz wird.

    Davon ganz abgesehen würd ich die Endlos-Schleife durch einen synchronized-Block und wait()/notify() ersetzen.
     
    Andro-medanebel bedankt sich.
  7. Andro-medanebel, 13.02.2011 #7
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Thread.currentThread() gibt sowohl in VariablenFuerActivityUndView.setHilfsvar(int i)
    als auch in MemoryActivity die Ausgabe "Thread[main,5,main]".
    Das interpretiere ich mal so, das beides im gleichen Thread läuft.

    Nun habe ich versucht, die Klasse VariablenFuerActivityUndView als eigenen Thread
    laufen zu lassen und habe folgende Änderungen im Programm vorgenommen:

    VariablenFuerActivityUndView.java:
    Code:
    package variablen_fuer_mehrere_klassen;
    
    import android.util.Log;
    
    public class VariablenFuerActivityUndView extends Thread {
     public static int hilfsvar = 0;
     public int getHilfsvar() {
        return hilfsvar;}
     synchronized public void setHilfsvar(int i) 
     { 
       //Log.d("setter Hilfsklasse","qqq"+Thread.currentThread());
       hilfsvar = i;
     }
     public void run() {
         setHilfsvar(1);
     }
    
    }
    
    CustomLayout.java:
    Code:
    protected void onSizeChanged(int w, int h, int ow, int oh){
    ...
    setzeHilfsvarAufEins();
    }
    
    public void setzeHilfsvarAufEins()
        {
            h.start();
            //h.setHilfsvar(1);
        }
    
    
    In MemoryActivity.java soll gewartet werden, bis
    h.hilfsvar auf 1 gesetzt wird:

    Code:
    synchronized (this) {
                if (h.getHilfsvar()==0){
                    try {wait();} catch(InterruptedException e) {}
    
                }
                notify();
            }
    
    Mit dem synchronized (this) lande ich allerdings in einer Endlosschleife.
    Woran kann das liegen?
     
    Zuletzt bearbeitet: 13.02.2011
  8. Zoopa, 14.02.2011 #8
    Zoopa

    Zoopa Android-Experte

    Beiträge:
    599
    Erhaltene Danke:
    173
    Registriert seit:
    28.07.2010
    Das Grundproblem ist immer noch dasselbe. Du wirst nicht drum herum kommen, deine Hilfsvar-Überprüfung in einen eigenen Thread zu packen.

    So wie du es jetzt hast, wird vermutlich der UI-Thread beim wait() schlafen gelegt und nie mehr durch ein notify() eines anderen Threads geweckt, wodurch dann dein ganzes GUI nicht mehr reagiert.

    Du willst vermutlich, dass ein Teil des Codes erst ausgeführt wird, wenn Hilfsvar = 1 ist. Daher könntest du die Überprüfung von Hilfsvar in einen eigenen Thread auslagern und zusätzlich in deiner Activity (MemoryActivity?) einen Handler definieren.

    Dann kannst du z.B. in deinem Prüf-Thread, sobald Hilfsvar == 1 ist, eine Message an den Handler im Main-Thread schicken, und dieser Handler führt dann den weiteren Code aus.

    Hier noch ein Blogeintrag und ein Google-Beispiel zum Thema.
     
    Andro-medanebel bedankt sich.
  9. maniac103, 14.02.2011 #9
    maniac103

    maniac103 Android-Lexikon

    Beiträge:
    1,237
    Erhaltene Danke:
    1,157
    Registriert seit:
    24.01.2011
    Für mich klingt's eher so, als ob die Activity (== UI-Thread) auf das Aufrufen eines View-Callbacks (UI-Callback aus dem Framework, also auch == UI-Thread) warten soll. Das geht nicht ;)

    Ich frage mich eher, was mit dem Warten erreicht werden soll? Was spricht dagegen, die Activity erst mal loslaufen zu lassen und später umzukonfigurieren?
     
    Andro-medanebel bedankt sich.
  10. Andro-medanebel, 14.02.2011 #10
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Ja, ich glaube es ist so. Meine Activity soll warten, bis im (Custom-)View
    automatisch onSizeChanged aufgerufen wurde.

    Mein CustomLayout hat je nach Device eine unterschiedliche Breite
    und Höhe, die aber erst - wie ich gelesen habe - bekannt ist, wenn
    onSizeChanged aufgerufen wurde.

    Die in onSizeChanged in der Klasse CustomLayout ermittelte
    Breite und Höhe meines CustomLayout muß ich wissen, bevor
    ich meine Activity fortführe, da ich abhängig von Breite und
    Höhe des CustomView/CustomLayout eine unterschiedliche Zahl von
    Buttons (Memorykarten) in meiner Activity erzeugen will.

    kleines Display=wenig Memorykarten(Buttons):
    ***
    ***
    ***
    ***
    großes Display=viele Memorykarten(Buttons):
    *******
    *******
    *******
    *******

    Auf den Buttons (später dann wohl ImageButtons) sollen
    Grafiken liegen, die ich aus res/drawable einlese.

    Auch dafür muß ich wissen, wie viele Buttons im Layout dargestellt
    werden können, denn wenn es z.B. nur 12 sind brauche ich nur
    sechs Grafiken einlesen, wenn ich 28 Buttons darstellen kann,
    muß ich dagegen 14 Images einlesen.
     
  11. Kranki, 14.02.2011 #11
    Kranki

    Kranki Ehrenmitglied

    Beiträge:
    3,831
    Erhaltene Danke:
    814
    Registriert seit:
    19.07.2009
    Tablet:
    Samsung Galaxy Tab 3 7.0 Lite
    Dann hab ich hier sechs Links für dich:

    Supporting Multiple Screens | Android Developers
    Android-er: Exercise: Get screen resolution using android.util.DisplayMetrics
    DisplayMetrics | Android Developers
    getWindowManager().getDefaultDisplay().getMetrics()

    Ach, und maniac103 hat dein Problem ganz richtig erkannt. Stell dir vor, du willst von deinem Schreibtisch aufstehen und in die Küche gehen, aber bleibst noch solange sitzen, bis du dir selber einen Kaffee gebracht hast - so läuft dein Programm gerade.
     
    Andro-medanebel bedankt sich.
  12. Andro-medanebel, 15.02.2011 #12
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Von der Methode mit DisplayMetrics hatte ich zwar schon gelesen,
    dachte aber, sie würde nicht taugen, da ich glaubte, die Beschreibung
    "The absolute height of the display in pixels." für width/heightPixels
    würde bedeuten, dass ich immer die gleiche Höhe und Breite
    erhalten würde unabhängig davon, ob ich Titel/Statuszeile ein-/ausblende.
    Das ist allerdings nicht so; Status- und Titelzeile werden von den
    Pixeln abgezogen, wenn ich sie einblende. Daher kann ich die Methode
    verwenden. Höhe und Breite über Höhe und Breite des Layouts
    zu ermitteln, hätte noch den Vorteil gehabt, dass meine Anwendung
    bei Android-Tablets, die Anwendungen nebeneinander anzeigen können,
    neben einer anderen Anwendung angezeigt werden könnte. Mit
    DisplayMetrics kann sie ja nur im Vollbildmodus laufen. Aber
    das ist wohl erst mal nicht so wichtig.

    Mit DisplayMetrics funktioniert es also :):

    Code:
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    Log.d("displaymetrics.widthPixels", ""+displaymetrics.widthPixels);
    Log.d("displaymetrics.heightPixels", ""+displaymetrics.heightPixels);
    
     
  13. Andro-medanebel, 15.02.2011 #13
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Habe mich jetzt ja für DisplayMetrics entschieden.
    Hatte vorher aber noch versucht, meine dynamische Button-
    Erzeugung von meiner Activity in mein CustomView zu verlegen;
    so wäre es unnötig, eine Methode zu finden, in meiner
    Activity solange zu warten, bis onSizeChanged des CustomView
    aufgerufen wird, da der CustomView schon selbst die Buttons erzeugt.

    Das Problem ist nur, dass das Button-Erzeugen dort nicht funktioniert:

    Button-Erzeugung in class MemoryActivity extends Activity {:
    Code:
    ...
    //Funktioniert!
    for(int i=0;i<anzahl_bilder;i++)
            {
             ib[i] = new ImageButton(this);
    ...
    
    Button-Erzeugung in class CustomLayout extends RelativeLayout{
    verschoben:
    Code:
    ...
    //Funktioniert nicht!
    for(int i=0;i<anzahl_bilder;i++)
            {
             ib[i] = new ImageButton(this);
             //Fehler: The constructor ImageButton(CustomLayout) is undefined
             //habe es mit ib[i] = new ImageButton(null); versucht.
             //Das gibt keinen Syntax- aber einen Laufzeitfehler.
    ...
    
    Gibt es eine einfache Änderung, mit der ich ImageButtons in
    meinem CustomView erzeugen kann?

    Wie gesagt, ich mache es jetzt mit DisplayMetrics, bin aber trotzdem
    neugierig, ob es mit einer kleinen Änderung auch möglich wäre,
    die Generierung der ImageButtons ins CustomView zu verschieben.

    Vielen Dank an alle, die mir geholfen haben.:)
     
  14. maniac103, 15.02.2011 #14
    maniac103

    maniac103 Android-Lexikon

    Beiträge:
    1,237
    Erhaltene Danke:
    1,157
    Registriert seit:
    24.01.2011
    Wie wär's damit?
    Code:
    for(int i=0;i<anzahl_bilder;i++)
            {
             ib[i] = new ImageButton(getContext());
    
    ;)

    Eine Activity implementiert immer einen Context, deswegen kannst du da direkt 'this' hinschreiben. Das Layout hat den Context als Member-Variable, deshalb der Getter.
     
  15. Andro-medanebel, 15.02.2011 #15
    Andro-medanebel

    Andro-medanebel Threadstarter Android-Hilfe.de Mitglied

    Beiträge:
    46
    Erhaltene Danke:
    0
    Registriert seit:
    09.10.2010
    Aha, danke.
     

Diese Seite empfehlen