In OnClickListener() auf Klassenvariable zugreifen

  • 15 Antworten
  • Letztes Antwortdatum
C

_Coco_

Neues Mitglied
1
Ahoi noch mal!
Ich habe ein Problem mit dem Zugriff auf eine Klassenvaribale innerhalb eines OnClickListener().
Folgender Code

Code:
public class Programme extends Activity 
{
    public String statusCODE;
    
    //Wird in einer anderen Klasse aufgerufen.
    //statusCODE wird auch mit einem Wert gefüllt.
    public void setVariable(String code)
    {
        statusCODE = code;
    }

    //... jede Menge andere Methoden

    View.OnClickListener SummerButtonHandler = new View.OnClickListener()
    {
        @Override
        public void onClick(View v) 
        {
               Log.i("STATUS", Programme.this.statusCODE);
         }
     }
}
wirft folgende Fehlermeldung aus (LogCat)
Code:
07-17 12:13:27.001: E/AndroidRuntime(25125): FATAL EXCEPTION: main
07-17 12:13:27.001: E/AndroidRuntime(25125): java.lang.NullPointerException: println needs a message
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.util.Log.println_native(Native Method)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.util.Log.i(Log.java:159)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at de.matthes.jmapp.Programme$3.onClick(Programme.java:225)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.view.View.performClick(View.java:4209)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.view.View$PerformClick.run(View.java:17431)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.os.Handler.handleCallback(Handler.java:725)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.os.Handler.dispatchMessage(Handler.java:92)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.os.Looper.loop(Looper.java:153)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at android.app.ActivityThread.main(ActivityThread.java:5297)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at java.lang.reflect.Method.invokeNative(Native Method)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at java.lang.reflect.Method.invoke(Method.java:511)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
07-17 12:13:27.001: E/AndroidRuntime(25125):     at dalvik.system.NativeStart.main(Native Method)

Also es kommt nix an. Ich bin Java-Neuling und bin mir sicher, dass es echt was ganz banales ist.
 
1.) Entweder wird dein OnClickListener vor dem ersten Aufruf von setVariable aufgerufen oder 2.) du übergibst bei setVariable ein null.

Gegen 1.) hilft: public String statusCODE = "<empty>";

Gegen 2.) solltest du eine Abfrage in setVariable einbauen.
 
Ich vermute eher du rufst in einer anderen Klasse zwar die richtige methode aber auf einem falschen Objekt auf.

Wie ruft die andere Methode denn die SetVariable auf?

Vorher mit einem new Programme()?
Dann setzt du das zwar in ein Objekt der Klasse Programme nur wird, wenn du die Activity öffnest ein anderes Objekt der gleichen Klasse benutzt und dort ist Statuscode dann nicht gesetzt.

Ansonsten verrat mir wie du an das richtige Objekt in der anderen Klasse kommst. :)
 
Danke erst mal euch beiden. Also die setVariable-Methode wird in einer asynchronen Klasse aufgerufen. Hier mal der Code dieser Klasse (die dafür da ist, den Status Code einer URL zu ermitteln).

Code:
class checkURL extends AsyncTask<String, String, String>
{
    private Programme activityProgramme = new Programme();

    @Override
    protected String doInBackground(String... uri) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpResponse response;
        String statusCode = null;
        try {
            response = httpclient.execute(new HttpGet(uri[0]));
            StatusLine statusLine = response.getStatusLine();
            statusCode = String.valueOf(statusLine.getStatusCode());
        } catch (ClientProtocolException e) {
            //TODO Handle problems..
        } catch (IOException e) {
            //TODO Handle problems..
        }
        return statusCode;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        [COLOR=Red][B]//result hat an dieser Stelle auf jeden Fall den Wert 200[/B][/COLOR]
        [B][COLOR=Red]activityProgramme.setVariable(result);[/COLOR][/B]
    }
}
Die asynchrone Klasse wird an folgender Stelle ausgeführt.

Code:
public class Programme extends Activity 
{
    public String statusCODE;
    
    //Wird in einer anderen Klasse aufgerufen.
    //statusCODE wird auch mit einem Wert gefüllt.
    public void setVariable(String code)
    {
        statusCODE = code;
        [B][COLOR=Red]//statusCODE hat an dieser Stelle auch definitiv den Wert 200[/COLOR][/B]
    }

    //... jede Menge andere Methoden

    View.OnClickListener SummerButtonHandler = new View.OnClickListener()
    {
        @Override
        public void onClick(View v) 
        {
[COLOR=Red] [B]                   checkURL get = new checkURL();
                  get.execute("http://www.google.de");[/B][/COLOR]

               [B][COLOR=Red]//Hier kommt der Wert 200 leider nicht mehr an[/COLOR][/B]
               Log.i("STATUS", Programme.this.statusCODE);
         }
     }
}
Wenn ich statusCODE mit public String statusCODE = ""; initialisiere, dann kommt zwar keine Fehlermeldung mehr, allerdings bleibt statusCODE leer im OnClickListener()-Event. :-(

Der ursprüngliche Beitrag von 09:36 Uhr wurde um 09:59 Uhr ergänzt:

Habe den Aufruf der async-Klasse mal in die onCreate-Methode von "Programme" getan und es hat den selben Effekt. Es hat also nix mit OnClickListener() zu tun.
 
Danke, ist schon mal einleuchtend. Ich muss sagen, dass ich als Newbie da echt noch meine Problemchen habe. Also ich habe jetzt die Async-Klasse angepasst:

Code:
class checkURL extends AsyncTask<String, String, String>
{
    public Programme activityProgramme;
    
    public checkURL(Programme obj)
    {
        activityProgramme = obj;
    }
    
    @Override
    protected String doInBackground(String... uri) {
        HttpClient httpclient = new DefaultHttpClient();
        HttpResponse response;
        String statusCode = null;
        try {
            response = httpclient.execute(new HttpGet(uri[0]));
            StatusLine statusLine = response.getStatusLine();
            statusCode = String.valueOf(statusLine.getStatusCode());
        } catch (ClientProtocolException e) {
            //TODO Handle problems..
        } catch (IOException e) {
            //TODO Handle problems..
        }
        return statusCode;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        activityProgramme.setVariable(result);
    }
}
Und in der Programme-Klasse den Code:

Code:
public class Programme extends Activity
{
    public String statusCODE;          
    
    public void setVariable(String code)
    {
        statusCODE = code;
         [B][COLOR=Red]//statusCODE hat an dieser Stelle immer noch den Wert 200[/COLOR][/B]       }

      //... jede Menge andere Methoden

      View.OnClickListener SummerButtonHandler = new View.OnClickListener()
     {
         @Override
         public void onClick(View v)
         {
      [COLOR=Red][B]           checkURL get = new checkURL(this);
                  get.execute("http://www.google.de");[/B][/COLOR]

               [B][COLOR=Red]//statusCODE immer noch leer
[/COLOR][/B]               Log.i("STATUSCODE", this.statusCODE);
          }
      }
}
Leider immer noch dieselbe Fehlermeldung. :-(

Der ursprüngliche Beitrag von 10:58 Uhr wurde um 11:01 Uhr ergänzt:

Auch wenn ich wie im Beispiel bei stackoverflow:

AsyncTask myTask = new MyTask(this);

also

AsyncTask<String, String, String> get = new checkURL (this);

nehme, selber Effekt. Ich dachte echt dass ich es jetzt endlich hätte.
 
Dann ist vermutlich die execute Methode nicht schnell genug. Du rufst die ja auf und direkt danach den Log. Bei beim asyncTask wird ja vom Rest des Programms nicht gewartet, bis die Ausführung beendet ist.

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
Hatte ich also recht ;)

Ich kann dir sagen warum das immer noch nicht funktioniert.
Weil der Task Asynchron ist.
Das heißt in deiner Activity geht es nach get.execute(...) SOFORT in die nächste Zeile das kann und wird vermutlich passieren bevor setvariable aufgerufen wird.
eine Http Abfrage braucht ja eine gewisse zeit bis zu deiner Log ausgabe hingegen vergeht praktisch keine zeit.

Was du machten könntest wäre das Log.i(...) in die postExecute Methode zu packen.
Weil du nur da sicher bist, dass deine Variable auch schon gesetzt wurde.
 
Hah, schneller gewesen :p

Kannst auch dem status des Tasks abfragen und den Log aufrufen, wenn er finished ist:
Code:
 task.getStatus() == AsyncTask.Status.FINISHED

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
Hm, ich dachte eigentlich immer protected void onPostExecute() wird immer nach Vollendung des Task ausgeführt. Und so war ich mir eigentlich immer sicher, dass setVariable() aufgerufen wird. Sie wird es ja auch und bekommt auch den Wert. Ich brauche die Variable statusCODE aber in der OnClickListener()

Die Abfrage:
Code:
        if(get.getStatus() == AsyncTask.Status.FINISHED)
        {
            Log.i("STATUSCODE", statusCODE);
        }
bringt zwar keine Fehlermeldung mehr, aber den Log leider auch nicht.
 
Da kannst du das mit ner while-schleife machen:
Code:
while(nicht finished){
Tue nichts;
} 
Hier loggen.

Oder du rufst was auch immer du mit dem code machst von onPostExecute auf, was wohl besser ist

Gesendet von meinem Galaxy Nexus mit der Android-Hilfe.de App
 
onPostExecute wird ja auch NACH dem Task aufgerufen.
Nochmal zur verdeutchlichung.
In dem Moment wo du den AsynTaks aufrufst hast du 2 Task einmal den, der die Downloads macht und deinen normalen wo du diesen Aufrufmachst.

In deinem normalen Task wird sofort innerhalb von millisekunden
Log.i("STATUSCODE", this.statusCODE);
aufgerufen.

der AsynTaks ist in der Zeit noch damit beschäftigt
httpclient.execute(new HttpGet(uri[0]));
auszuführen.
Das heißt das postExecute wird erst ausgeführt NACHDEM du schon versuchts in das Log zu schreiben, deshalb ist an dieser Stelle dein
stausCode
noch null und es funktioniert nicht.

Und die Methode mit while(nicht finished) würde ich nicht benutzen, dann könntest du das ganze auch direkt ohne AsynTaks machen (Ok das erlaubt Android mittlerweile nicht mehr)
Aber wenn der Asyntask zu lange braucht stürzt deine Anwendung auch ab und in der Zeit wo du in dieser While Schleife bist friert deine App auch ein.

Schreib dir eine methode in deine Programme Klasse die z.B. logOnPostExecute() heißt.
In dieser Methode machst du deine Logausgabe.
Und in der onPostExecute Methode rufst du dann die logOnPostExecute Methode auf.

Wobei du dann das Log auch direkt in der onLogPostExecute Methode aufrufen kannst.

Ich hoffe das war verständlich, wenn nicht mal ich dir noch ein Diagramm dazu :D
 
Danke euch! amfa, jetzt habe ich es verstanden. Ich habe den Code, der ausgeführt werden soll, wenn StatusCode == 200, in die setVariable()-Methode (ist ja dasselbe wie deine vorgeschlagene logOnPostExecute()-Methode) gepackt und lasse sie schlicht parallel zum OnClickListener() laufen. Klappt super.

Hier für alle, die mal vor demselben Problem stehen:

Programme-Klasse
Code:
public class Programme extends Activity
{
    public String statusCODE;          
    
    public void setVariable(String code)
    {
        statusCODE = code;
        Log.i("STATUSCODE", statusCODE);
        //.... oder was auch immer mit dem Wert aus dem Async-Task passieren soll
    }

      //... jede Menge andere Methoden

      View.OnClickListener SummerButtonHandler = new View.OnClickListener()
     {
         @Override
         public void onClick(View v)
         {
                 checkURL get = new checkURL(this);
                  get.execute("http://www.google.de");
          }
      }
}

Vieeeelen Dank! Letzten Endes sind wir 1x um die Welt gereist, nur um am Ende wieder am Anfang (=richtiger Weg) zu stehen!
 
Sehr gut :)
Multithreading ist nicht so einfach zu verstehen für Anfänger. (Selbst Profis kämpfen da oftmals noch mit details)
 
amfa schrieb:
(Selbst Profis kämpfen da oftmals noch mit details)

Ooooh ja. :D
Hier zur allgemeinen Erheiterung ein Kleinod aus meinem Horrorkabinett: Wer kommt schon darauf, dass der Wert von x sich zwischen den beiden folgenden Vergleichen ändern könnte:
Code:
if( x<0 || x>MAX ) { ... }
 
Das is aber auch ganz mieses timing würde ich sagen :D
 
Zurück
Oben Unten